Rohen Giralt
03/26/2026, 6:37 PMimport java.util.*
fun main() {
val x: Any = LinkedList<Int>().apply { add(0) }
foo(x)
}
fun <T> foo(obj: T) {
if (obj == arrayListOf(0)) {
obj.ensureCapacity(100)
}
}
Surprisingly, this compiles with no warnings, but fails with a ClassCastException at runtime. That's because the obj == arrayListOf(0) line causes a smart cast of obj from T to ArrayList<T>. But because List#equals is defined such that any two lists with the same elements (of any concrete type) are equal, the smart cast here is unsafe.
Even more surprisingly to me, this behavior only appears when obj has a generic type parameter as its type. The following example fails to compile:
import java.util.*
fun main() {
val x: Any = LinkedList<Int>().apply { add(0) }
foo(x)
}
fun foo(obj: Any) {
if (obj == arrayListOf(0)) {
obj.ensureCapacity(100)
}
}
I'm curious what's going on here. Why does the compiler accept the first example, though it's unsafe? And given that it accepts the first, why doesn't it accept the second?dmitriy.novozhilov
03/27/2026, 8:24 AM