scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Bitwise operators on bytes #8718

Closed scabug closed 11 months ago

scabug commented 10 years ago

First time reporting a bug, so if it's wrong please correct me.

I can't get this working:

scala> var a: Byte = 5 | 3 a: Byte = 7

scala> a |= 7

:9: error: type mismatch; found : Int required: Byte a |= 7 ^ scala> a |= 7.toByte :9: error: type mismatch; found : Int required: Byte a |= 7.toByte ^ scala> a |= 7 :9: error: type mismatch; found : Int required: Byte a |= 7 ^ It seems like bit operators aren't working on bytes, is this a bug?
scabug commented 10 years ago

Imported From: https://issues.scala-lang.org/browse/SI-8718?orig=1 Reporter: Johan Stenberg (johanstenberg) Affected Versions: 2.11.0

scabug commented 10 years ago

Malte Isberner (misberner) said: This is limited neither to Bytes nor bitwise operators. In fact, all non-simple assignment operators are broken for Byte, Char, Short. The reason is that in Java (and Scala adopts this) arithmetic (including bitwise) expressions are always of type int, unless at least one of their operands is of type long (then they are of type long). This leads to some weird behaviors:

byte x = 0;
byte y = 1;
byte z = x + y; // error: cannot convert from int to byte

Here, x + y is of type int, even though both are of type byte. The solution is to explicitly convert them to byte:

byte z = (byte)(x + y);

Things are different for the non-simple assignment operators (+= etc.): Even though one would think that x += y is equivalent to x = x + y, for the above reason this is not true: if x is of type T, then x += y is in fact equivalent to x = (T)(x + y). This does lead to some unexpected results:

x += y; // OK
x += 1000000000000L; // also OK!

So Scala adapts all these weird behaviors from Java, but omits the explicit downcast in the non-simple assignment operators...

SethTisue commented 11 months ago

this is working as designed, for better or worse. it's equally unfortunate in Java. I'm not aware of anyone having seriously looked into improving the situation in Scala instead of just carrying over the design from Java. in any case, changes in this area seem unlikely, for Scala 2 anyway

Ichoran commented 11 months ago

For the record, one can get whatever behavior one wants with opaque types in Scala 3. You could define opaque type Bite = Byte and define +, |, etc. to all be whatever you think is more sane. There is a little bit of syntactic overhead, but you can get it down to a .b or somesuch here and there.

I've done this with unsigned bytes, for instance.

som-snytt commented 11 months ago

Also to clarify for the record

scala> var x: Byte = 1
var x: Byte = 1

scala> val y: Byte = 2
val y: Byte = 2

scala> x + y
val res0: Int = 3

scala> x += y
         ^
       error: value += is not a member of Byte
         Expression does not convert to assignment because:
           type mismatch;
            found   : Int
            required: Byte
           expansion: x = x.+(y)

scala> implicit def cv(i: Int): Byte = i.toByte
                    ^
       warning: implicit conversion method cv should be enabled
       by making the implicit value scala.language.implicitConversions visible.
       This can be achieved by adding the import clause 'import scala.language.implicitConversions'
       or by setting the compiler option -language:implicitConversions.
       See the Scaladoc for value scala.language.implicitConversions for a discussion
       why the feature should be explicitly enabled.
def cv(i: Int): Byte

scala> x += y

scala> x
val res3: Byte = 3