What are the differences between asInstanceOf[T] and (o: T) in Scala?
foo.asInstanceOf[Bar]
is a type cast, which is primarily a runtime operation. It says that the compiler should be coerced into believing thatfoo
is aBar
. This may result in an error (aClassCastException
) if and whenfoo
is evaluated to be something other than aBar
at runtime.foo:Bar
is a type ascription, which is entirely a compile-time operation. This is giving the compiler assistance in understanding the meaning of your code, without forcing it to believe anything that could possibly be untrue; no runtime failures can result from the use of type ascriptions.
Type ascriptions can also be used to trigger implicit conversions. For instance, you could define the following implicit conversion:
implicit def foo(s:String):Int = s.length
and then ensure its use like so:
scala> "hi":Int
res29: Int = 2
Ascribing type Int
to a String
would normally be a compile-time type error, but before giving up the compiler will search for available implicit conversions to make the problem go away. The particular implicit conversion that will be used in a given context is known at compile time.
Needless to say, runtime errors are undesirable, so the extent to which you can specify things in a type-safe manner (without using asInstanceof
), the better! If you find yourself using asInstanceOf
, you should probably be using match
instead.
Pelotom's answer covers the theory pretty nice, here are some examples to make it clearer:
def foo(x: Any) {
println("any")
}
def foo(x: String) {
println("string")
}
def main(args: Array[String]) {
val a: Any = new Object
val s = "string"
foo(a) // any
foo(s) // string
foo(s: Any) // any
foo(a.asInstanceOf[String]) // compiles, but ClassCastException during runtime
foo(a: String) // does not compile, type mismatch
}
As you can see the type ascription can be used to resolve disambiguations. Sometimes they can be unresolvable by the compiler (see later), which will report an error and you must resolve it. In other cases (like in the example) it just uses the "wrong" method, not that you want. foo(a: String)
does not compile, showing that the type ascription is not a cast. Compare it with the previous line, where the compiler is happy, but you get an exception, so the error is detected then with the type ascription.
You will get an unresolvable ambiguity if you also add a method
def foo(xs: Any*) {
println("vararg")
}
In this case the first and third invocation of foo will not compile, as the compiler can not decide if you want to call the foo with a single Any param, or with the varargs, as both of them seems to be equally good => you must use a type ascription to help the compiler.
Edit see also What is the purpose of type ascription in Scala?