Kevin Del Castillo
12/09/2022, 7:23 PMKotlin has several unsound exceptions, in part due to its goal to interoperate with Java. As you can see in this Kotlin example, generic types can trigger cases where null values can flow into a list declared as holding non-null elements.I understand why Java libraries can sometimes be troublesome (
T!
), but I'm a bit confused about the generic types example they're giving, this is the offending code:
private fun <E> List<E>.addAnything(element: E) {
if (this is MutableList<E>) { this.add(element) }
}
fun main() {
// A list of non-null Ints.
var myList : List<Int> = arrayListOf(1, 2, 42)
// Add a null.
myList.addAnything(null)
// Add a non-number.
myList.addAnything("This is not even a number")
// Print resulting list, not matching `List<Int>`.
print(myList);
}
Which prints:
[1, 2, 42, null, This is not even a number]
Why is this happening? My first guess is that the if
in addAnything
is true because of type-erasure, is this correct?mkrussel
12/09/2022, 8:00 PME
is completely ignored in the runtime type check due to type erasure.
The other issue is that with Kotln. List<Number>
is a subtype of List<Number?>
, but MutableList<Number>
is not a subtype of MutableList<Number?>
. So the normal type checking would prevent this logic, but the type erased unsafe cast to MutableList
breaks the compiler safety.
The string works for the same reason. List<Int>
is a subtype of List<Any>
so the compiler calls the extension function assuming that you wanted the list to be of type List<Any>
.Pablichjenkov
12/10/2022, 2:38 AMunsafe casting
, you are aware it could be messy.ilya.gorbunov
12/11/2022, 2:00 PMPablichjenkov
12/11/2022, 4:28 PMUberto Barbini
01/14/2023, 1:11 AM