Reputation: 45
I got a few question when I was reading the Kotlin reference:
In "Type erasure and generic type checks", it mention:
When you already have the type arguments of an instance checked statically (at compile time), you can make an is-check or a cast that involves the non-generic part of the type. Note that angle brackets are omitted in this case
and they gave a example:
fun handleStrings(list: List<String>) {
if (list is ArrayList) {
// `list` is smart-cast to `ArrayList<String>`
}
}
Q1: I test myself
val a = mutableListOf(1, 2, 3)
val b = listOf(1, 2, 3)
println(a is List) //error, should use List<*>
println(b is MutableList) //can compile
I don't understand why they got different result.
Q2: I found that I can't use smart cast from List to ArrayList
println(listOf(1, 2, 3) is ArrayList) //false
println(listOf(1, 2, 3) is MutableList) //true
As I remember, listOf() is implement by ArrayList in Kotlin, it calls asList
, which return a ArrayList, in Arrays.java.
So, why can't listOf() smart cast to ArrayList?
Upvotes: 1
Views: 66
Reputation: 3890
A1: In the first case, you cast from subclass to superclass. It does not make any sense, since instance of subclass can always be used as an instance of superclass without casting:
val a: MutableList<Int> = mutableList(1, 2, 3)
val b: List<Int> = a
So the Kotlin compiler does not implement generic smart cast for casting upstairs and uses default rules of casting which require star projection.
In the second case you cast from superclass to subclass, so it works as intended.
A2: There are two different ArrayList
classes. Try to run this code:
println(listOf(1, 2, 3)::class)
println(ArrayList<String>()::class)
It prints:
class java.util.Arrays$ArrayList
class java.util.ArrayList
listOf
returns a nested class Arrays.ArrayList
, not ArrayList
you usually work with.
Upvotes: 3