Difference between List and Mutable List in Kotlin Generics

517 Views Asked by At

I recently study about kotlin Generics, But i found some weird stituation

IDE image

interface MyItem

fun <ITEM : MyItem> bindItem(items: List<ITEM>?) {
    val castedItem = items as List<MyItem>?
}

fun <ITEM : MyItem> bindItem2(items: MutableList<ITEM>?) {
    val castedItem = items as MutableList<MyItem>?
}

Only In MutableList case compiler warn about unchecked Cast

If anyone knows about this situation, Please tell me about this.

1

There are 1 best solutions below

0
On

The List interface has declaration site covariance (<out T>). This means it is safe to "upcast" the type because a List only ever outputs items. For example, if you have a List<Int>, it is safe to use it as a List<Number> because an Int can always be safely cast to a Number. When you retrieve items from the list, they always satisfy being the type Int or the supertype Number.

MutableList does not have a covariant type. It is invariant at the declaration site. This means it is not inherently safe to "upcast" its type. For example, if you cast your MutableList<Int> to a MutableList<Number>, it is not safe to use the MutableList<Number> reference, because it would let you add a Float to the list. When the original reference is used as a MutableList<Int> and tries to retrieve a value from it, it will get a ClassCastException for trying to use the Float as an Int.

In this case, you could safely cast the MutableList to a covariant type, like this:

val castedItem = items as MutableList<out MyItem>?

but a MutableList with a covariant type is not really any different than a List (except that you can clear() it), so it would be better to cast it to a List<MyItem> to make the intent clearer.