FredSuvn
FredSuvn

Reputation: 2087

What's the difference between T and T? in Kotlin?

What's the difference between:

fun <T, R> List<T>.map1(transform: (T) -> R): List<R> {
    return this.map(transform)
}

and

fun <T, R> List<T>.map2(transform: (T?) -> R): List<R> {
    return this.map(transform)
}

and

fun <T, R> List<T?>.map3(transform: (T?) -> R): List<R> {
    return this.map(transform)
}

In my test, null is accepted for all 3 transform functions above, so: Is there any difference between T and T??

Upvotes: 7

Views: 433

Answers (1)

Sam
Sam

Reputation: 9944

In your examples, T and T? are equivalent, but there are other cases where the ? does make a difference.

When you declare a type parameter <T>, it doesn't have any restrictions on it. It's the same as writing <T: Any?>, and it means T will allow any sub-type of Any?. Adding a ? to it would make it nullable, but Any? is already nullable, so the ? doesn't change anything. That means that the set of types allowed by an unbounded type T is the same as the set of types allowed by T?.

As soon as you put restrictions on what T can be, things change, though. For example, in the following function, we declare a type parameter <T: Any>, restricting it so it's no longer nullable.

fun <T: Any> myFunction(item: T) // item can't be null

That means I can't pass null to myFunction. I can only call the function with a null argument if I change the type of the parameter to be T?.

fun <T: Any> myFunction(item: T?) // item can be null

Note that the ? just annotates an existing type parameter. Declaring a type parameter with a ? doesn't mean anything and doesn't compile. For example, fun <T?> myFunction(item: T) isn't valid Kotlin code.

Upvotes: 7

Related Questions