I don't know if I am overreacting, but just realized that
has changed its meaning from unsigned shit to sign preserving shift. IMHO this breaks a lot of code in a very dangerous way. A more thoughtful solution would have been to introduce a sign preserving operator
or something like that. Now we have a complete mess of old code in not well maintained but still working libraries with
meaning a complete different thing than in new libraries. How can I rely on that a library is working correctly if I don't know what kind of
the author had in mind when writing the library ? How do I use code with two libraries, one written with old
and another with new
?
But please show me that I am wrong !
I have not been able to reproduce this behavior. On my Manjaro Linux with the last development version (built with choosenim) shr is a logical right shift, not an arithmetic one. This is also the case with the last stable version.
And there is already an arithmetic right shift in the system module. This a function (not an operator) named ashr.
I have not been able to reproduce
Well, it is very confusing. I looked in 019.9 docs this morning, and indeed it was said that shr behaves as ashr. But example was stlll like shr, and additional a separate ashr was mentioned. So maybe just a bug in docs. Otherwise for sure adrianv would be right, as it would be a drastic change, and name shr is bad for arithmetic shift.
Yes, there is indeed a change in the documentation between 0.19.6 and 0.19.9.
Personally, for signed integers I would find more consistent to use an arithmetic shift to the right. With a logical shift, -2 shr 1 is equal to 9223372036854775807 on a 64 bits machine which may seem odd. We would rather expect to get -1.
In C, the shift to the right is arithmetic for signed integers, logical for unsigned integers, which makes sense. And to get a logical shift for a signed integer, you have only to cast it to an unsigned int.
Now, as shr has always been a logical shift, I agree that it would be a questionable change which could break code in some subtile ways.
Because we can then deprecate ashr.
@Araq, it would be great to get rid of that!
However, as per the latest documentation for shr:
...filling vacant bit positions with the sign bit.
This would mean that a shr of a "minus one" of any type should do the same as a no-op whereas a shr of any unsigned integers should zero fill as there is no "sign bit".
However, at least for version 0.19.9, it doesn't do as advertised, with the first group using unsigned behaving as expected, the second group passing when they shouldn't and the third group failing when they should pass:
doAssert 0xFF'u8 shr 1 == 0x7F'u8
doAssert 0xFFFF'u16 shr 1 == 0x7FFF'u16
doAssert 0xFFFFFFFF'u32 shr 1 == 0x7FFFFFFF'u32
doAssert 0xFFFFFFFFFFFFFFFF'u64 shr 1 == 0x7FFFFFFFFFFFFFFF'u64
doAssert 0xFFFFFFFFFFFFFFFF'u shr 1 == 0x7FFFFFFFFFFFFFFF'u
doAssert -1'i8 shr 1 == 0x7F'i8
doAssert -1'i16 shr 1 == 0x7FFF'i16
doAssert -1'i32 shr 1 == 0x7FFFFFFF'i32
doAssert -1'i64 shr 1 == 0x7FFFFFFFFFFFFFFF'i64
doAssert -1 shr 1 == 0x7FFFFFFFFFFFFFFF
doAssert -1'i8 shr 1 == -1'i8
doAssert -1'i16 shr 1 == -1'i16
doAssert -1'i32 shr 1 == -1'i32
doAssert -1'i64 shr 1 == -1'i64
doAssert -1 shr 1 == -1
As per the following Wandbox: https://wandbox.org/permlink/jwX8vctgMmTxoTVN
When this works as advertised (including examples showing these edge cases of the most significant bit set) it will be great, as it then works the same as logical languages like F# where the behaviour depends on the unsigned or not integer type.