In Kotlin, when writing a generic, non-inline function, x is T
throws a compiler error due to type erasure.
fun <T> example(foo: Any, bar: T) {
if (foo is T) { // compile error
// ...
}
}
However x as? T
is perfectly fine, it seems (although does throw the usual "unchecked cast" warning). Why can't the compiler just replace x is T
with (x as? T) != null
? Is there a difference between these?
fun <T> example(foo: Any, bar: T) {
if ((foo as? T) != null) { // no compile error
// ...
}
}
This is explained in document Generics type checks and casts
Due to the type erasure, there is no general way to check whether an instance of a generic type was created with certain type arguments at runtime, and the compiler prohibits such is-checks such as ints is List or list is T (type parameter).
Explained why is
is not allowed.
And
... The type arguments of generic function calls are also only checked at compile time. Inside the function bodies, the type parameters cannot be used for type checks, and type casts to type parameters (foo as T) are unchecked
state that foo as? T
is unchecked, just like foo as? Any
.
We can verify this by running below
public fun <T> asExample(foo: Any, bar: T): Boolean {
if ((foo as? T) != null) { // no compile error
return true
}
return false
}
public fun main() {
println(asExample("A", "B"))
println(asExample("A", 0))
}
Which will print
true
true
Related: What is difference between "as" and "is" operator in Kotlin?