Search code examples
kotlincovariance

Kotlin - nullable receiver extension won't accept non-nullable equivalent


Consider the following example:

class Foo<T>

fun <T> Foo<Iterable<T>?>.bar(i: Iterable<T>) {
    ...
}

Class Foo has an extension method, bar which requires a receiver of Iterable<T>?

Consider the following use-case:

val x = listOf(123, 456)
val f = Foo<Iterable<Int>>()

f.bar(x)

Compiler error on f:

Type mismatch

Required: Foo<Iterable<Int>?>

Found: Foo<Iterable<Int>>

I could understand this not working the other way around, trying to pass a nullable type to a non-nullable receiver, but I don't understand why I can't pass a non-nullable to a nullable receiver.

Essentially I'm trying to say "The receiver may be null, but in this case, I can guarantee it isn't"

Any thoughts on how to fix this, so the extension method will allow both nullable and non-nullable types?

Note: I cannot change val f = Foo<Iterable<Int>> to val f = Foo<Iterable<Int>?> because this is automatically decided based on the type of a property.


Solution

  • Just add out modifier and it will work:

    class Foo<out T>
    

    We use out modifier to indicate covariance (similar to "? extends T" in Java). Covariance - is the ability to change the generic type argument from a class to one of its parents, i.e. assign List<String> to List<Any>.

    Here are docs about generics.