Grozz
Grozz

Reputation: 8425

Scala weird behavior for type conversion in generic function

Could anyone explain why that happens?

scala> def as[T](v: Any) = Try(v.asInstanceOf[T])
as: [T](v: Any)scala.util.Try[T]

scala> as[Int]("Hello")
res0: scala.util.Try[Int] = Success(Hello)

scala> res0.map(_ + 1)
res1: scala.util.Try[Int] = Failure(java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer)

It's not about boxing because you could use your own type instead of Int and it behaves the same way.

Doesn't seem to be about by-name parameter either, because you could replace Try with Option and it will be the same.

I'm guessing it's about erasure, but maybe somebody could give a detailed explanation?

Upvotes: 1

Views: 61

Answers (1)

Michael Zajac
Michael Zajac

Reputation: 55569

It's all in the scaladoc:

Note that the success of a cast at runtime is modulo Scala's erasure semantics. Therefore the expression 1.asInstanceOf[String] will throw a ClassCastException at runtime, while the expression List(1).asInstanceOf[List[String]] will not. In the latter example, because the type argument is erased as part of compilation it is not possible to check whether the contents of the list are of the requested type.

So, because T is erased, Try(v.asInstanceOf[T]) will not immediately throw a ClassCastException, because as far as the JVM knows, you have a Try[Any]. But as soon as you try to treat the contained type like an Int, you trigger the exception.

Upvotes: 4

Related Questions