I was trying to answer this question, as I thought I knew the answer. Turns out, I did not know quite enough :/
Here is a test I have done:
class Inst[T] {
def is(x: Any) = scala.util.Try { as(x) }.isSuccess
def as(x: Any): T = x.asInstanceOf[T]
}
scala> new Inst[String].is(3)
res17: Boolean = true
scala> new Inst[String].as(3)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
... 33 elided
What is going on here? Why does only the second call to as
throw, but not the first one?
This is because the class-cast-exception is only thrown when you do something with the value, call a method on it after the cast. In the REPL for example, you would have a toString
call in the second case. Note:
new Inst[String].as(3); () // nothing happens
new Inst[String].as(3).toString; () // exception
The reason why this takes the extra step is that Inst[T]
is generic with type parameter T
which is erased at runtime; only when the call-site (that has a static knowledge of type T
) tries to call a method on the result, the actual type check occurs.
For your follow-up question, toString
is defined on any object and since T
is generic you have a boxed integer (<: AnyRef
) and toString
and println
succeed within the is
method. So another example where the Try
would fail is this:
class Inst[T] {
def foo(x: Any)(implicit ev: T <:< String) = scala.util.Try {
ev(as(x)).reverse
}.isSuccess
}
new Inst[String].foo(3) // false!
While @0__'s answer explains why it doesn't work, here is how to make it work:
class Inst[T](implicit tag: scala.reflect.ClassTag[T]) {
def is(x: Any) = tag.runtimeClass.isInstance(x)
// scala.util.Try { as(x) }.isSuccess will work as well
def as(x: Any): T = tag.runtimeClass.cast(x).asInstanceOf[T]
}
object Main extends App {
println(new Inst[String].is(3))
println(new Inst[String].as(3))
}
false
java.lang.ClassCastException: Cannot cast java.lang.Integer to java.lang.String
at java.lang.Class.cast(Class.java:3369)
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With