LiTTle
LiTTle

Reputation: 1881

Kotlin Generics type parameters

At the following source code

fun main(args: Array<String>) {
    println("Hello, world!")

    val mutableIntList = mutableListOf(1, 2, 3)

    addInt(4, mutableIntList) // No compile-time error
    addAnotherInt(5, mutableIntList) // Compile-time error

    println(mutableIntList)

}

fun <T: Number> addInt(item:T,
                       list:MutableList<in T>){
    list.add(item)
}

fun <T: Number> addAnotherInt(item:T,
                              list:MutableList<in Number>){
    list.add(item)
}

The functions addInt and addAnotherInt take as an argument a contravariant MutableList of Number. But at the main function one line compiles normally and the other is not.

I also checked the generated java code from these functions and they seem identical.

What could be the difference between the functions addInt and addAnotherInt?

Upvotes: 6

Views: 1633

Answers (2)

Marko Topolnik
Marko Topolnik

Reputation: 200266

in Number means "Number or its supertype". Int is not a "Number or its supertype", it is its subtype.

In plain words, you declared that your addAnotherInt() wants a list that is at least as general as accepting any kind of Number.

By contrast, addInt declares item: T and list: MutableList<in T>. T itself is declared as a free type variable for the function, which means it will be bound at each specific call site. So when you say

addInt(4, mutableIntList)

Kotlin binds T to Int based on the first argument and propagates this to the second argument, which is now MutableList<in Int>. You passed in a MutableList<Int> which is compatible with that type, so Kotlin is satisified.

If you declared

val mutableIntList: MutableList<Number> = mutableListOf(1, 2, 3)

then the code would compile because now the list is as general as required, and you can add any Number to it.

Upvotes: 10

tynn
tynn

Reputation: 39873

Your code will compile with a number list:

val mutableIntList = mutableListOf<Number>(1, 2, 3)

But since the type is inferred to MutableList<Int>, you can't use it as a MutableList<in Number>. This translates to the Java equivalent MutableList<? super Number> and means that you can add any Number to the list. But adding a Long to the MutableList<Int> is not possible.

Your second method addInt() is a little more strict and translates MutableList<? super Int> in your usecase. Thus you can use it as such. Both methods are capable of using a MutableList<Number> though.

Upvotes: 2

Related Questions