4

I can cast Int data to Byte.

scala> 10.asInstanceOf[Byte]
res8: Byte = 10

However with the same value in Any type, the cast raises an error.

scala> val x : Any = 10
x: Any = 10

scala> x.asInstanceOf[Byte]
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Byte
    at scala.runtime.BoxesRunTime.unboxToByte(BoxesRunTime.java:98)
    at .<init>(<console>:10)

I can cast twice.

scala> val y = x.asInstanceOf[Int]
y: Int = 10

scala> y.asInstanceOf[Byte]
res11: Byte = 10

Are there better ways than this?

1
  • 3
    Please note that you don't need 10.asInstanceOf[Byte]. 10.toByte works just fine. Commented Aug 13, 2014 at 14:19

3 Answers 3

7

In Scala, compiler tries to hide the distinction between primitive types and reference ones (boxed), defaulting to primitives. Sometimes, abstractions leak and you see that kind of problems.

Here, you're pretending that value is Any, which require compiler to fallback to boxed values:

override def set(value:Any) = {
    if (check(value.asInstanceOf[Byte])) {

And here, you're not limiting value to be referential, so such casting will be done on primitive types:

10.asInstanceOf[Byte]

In other words:

scala> val x: Any = 10
x: Any = 10

scala> x.asInstanceOf[Byte]
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Byte
  at scala.runtime.BoxesRunTime.unboxToByte(BoxesRunTime.java:97)
  ... 32 elided

scala> val y: Int = 10
y: Int = 10

scala> y.asInstanceOf[Byte]
res4: Byte = 10

To overcome this problem, you probably have to go through an extra conversion to, say, String:

scala> x.toString.toInt
res6: Int = 10

scala> x.toString.toByte
res7: Byte = 10
Sign up to request clarification or add additional context in comments.

6 Comments

+1 since your answer really explain why this happens, does this regression form Any to the java primitive types happens only when trying to cast a type from Any to some subtype?
I like the explanation, but not so much the solution. I'd go with @EndeNeu's one.
@EndeNeu when they're boxed, so with AnyVal as well (see the second sentence).
@IonuțG.Stan okay. BTW, alternatively, you can explicitly unbox the value: scala.runtime.BoxesRunTime.unboxToInt(y).asInstanceOf[Byte]
Wouldn't it be faster to do x.asInstanceOf[Number].intValue()?
|
3

Try converting to int and then to Byte:

scala> val x : Any = 10
x: Any = 10

scala> x.asInstanceOf[Int].asInstanceOf[Byte]
res1: Byte = 10

Or as Ionuț G. Stan suggested:

scala> x.asInstanceOf[Int].toByte
res4: Byte = 10

Although I cannot explain why this work.

3 Comments

+1 I'd replace x.asInstanceOf[Int].asInstanceOf[Byte] with x.asInstanceOf[Int].toByte, though.
The reason this works is because you are casting up to the super-type for anything, which is Any, then down casting to byte. Here is the type hierarchy in scala scala-lang.org/old/node/128
@ChrisStewart thanks for the explanation, and thanks to Ionut for the nice catch.
0

An integer is 32 bits in Java, while a byte is obviously 8 bits. The problem is what bits do you truncate to make an integer a byte? The least significant 24 bits or the most significant 24 bits? The correct answer is in the context of your problem.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.