import unsigned
var x: uint64 = 0
x += 1'u64
I get:
x.nim(3, 4) Error: type mismatch: got (uint64, uint64) but expected one of: system.+=(x: var T, y: T) system.+=(x: var T, y: T)
After twiddling with it for long I notice that the issue doesn't happen when += is not a generic proc. I read all the docs can't figure out what is wrong. Can anyone explain why doesn't it work?
OK, thanks for the info. I used unsigned because for my hello world (which is a hash function)...but I really don't care. I may be able to do it sensibly with signed int64s, but I need a clarification of 2 language features that doesn't seem to be documented: representation and overflow semantics. Can I assume a 2's complement? Can I assume signed into overflow to return what a mathematical function would, truncated to 64 bits, including all the funny effects like multiplying positive numbers and getting a negative result? I used unsigned because in the total lack of knowledge it seemed safer (and also it's more natural - regular modulo arithmetic is a cleaner concept than a shifted one, but really - bits are bits). I see that with second-class treatment it may not have been so.
BTW, I wonder what's the reason for the hate for unsigned types. I tried to search the forum, but I can't find a built-in search and the last 15 pages don't contain a word 'unsigned' in their titles. I think it should be a part of documentation. When I saw that unsigned is moved away for discouragement, I thought 'funny, I have to ask about it one day' and at least initially - ignore. I don't think I'm the only one who doesn't respect the rules that they don't understand.
Ok, here is my rant:
for i in 0 .. x.len-3 shouldn't iterate when x.len == 0. No, x.len-3 should not wrap around to some large number. No, it shouldn't raise an underflow exception either. No, I don't care if you're smart and know len produces a natural number and thus could use an unsigned integer to store it. No, I don't care if you want to access a 3GB large array in your 32bit address space. I prefer subtraction to work instead. This one single bit for the sign (I know it's not really a bit) is really worth paying.
Representation and overflow semantics are this way: Signed integers raise an exception on over-/underflow and unsigned integers provide the modulo semantics. In release mode the overflow checking is turned off because it's expensive unfortunately, but the optimizer is free to assume no overflow / wrap around can happen.
It's safe to assume a 2's complement though I often think chip designers should have made low(int) a NaN for integers or something like that. I consider it a big design mistake that there is a negative number that has no positive counterpart.
OK, I wrote a custom += for uint64.
In the field where I wanted to use Nimrod (various data transforms; checksums, compression, encryption) workload looks like this:
To get fair efficiency on 64-bit platforms, one has to use either SIMD or 64-bit variables, so either int64 or uint64 or vectors are necessary. The latter is unavailable, so I have to skip it for now. Checksums and encryption commonly use multiplication with modulo semantics because it is fast on most modern CPUs and multiplication by a prime shifts information to the more significant bits nicely. But overflow is needed here. They use bit rotations (even more often) to shift in the opposite direction - and these are implemented more efficiently when overflow is allowed (and actually C compilers recognise rotations as such and do them as 1 instruction, at least on AMD64). Compression algos, except for slow ones, rely heavily of hash tables. And the fastest hashes are multiplication based too.
I told it to show that there's a field where unsigned integers make a lot of sense. Treating them bad is going to make some class of coders that are potential Nimrod users uneasy.
BTW, it would be nice to be able to treat any proc with appropriate number of arguments as an operator.
When we have:
a shl 10
then
a rotl 10
looks better than
rotl(a, 10)
The syntax is not that bad if you use dots:
proc mul(a, b: int): int =
result = a * b
var
a = 2
b = 4
c = 6
c = a.mul(b)
echo a, b, c