Search code examples
genericskotlincontravariance

Contravariance in Kotlin


I never truly understood generics in Java, so it seems to be the case with Kotlin. Consider the following code snippet (it's a contrived example):

class AnyComparator: Comparator<Any> {
    override fun compare(o1: Any, o2: Any): Int {
        TODO("not implemented")
    }
}


fun <T> test() {
    val x: Comparator<in Double> = AnyComparator() // OK!
    val y: Comparator<in T> = AnyComparator() // Compilation error
}

The second assignment fails with the error

Type mismatch. 
Required: kotlin.Comparator<in T>
Found: AnyComparator

Now, if I understand correctly the in modifier indicates the T is only consumed by the generic type Comparator (it makes contravariant), so I should be able to assign any Comparator with type argument E which is the base class of T. Based on this, I should be able to assign AnyComparator to both variables x and y, since the type Any is the base class of every class in Kotlin. It turns out I can't, and I don't understand why.


Solution

  • It can be seem strange but Any is not the superclass of all kotlin classes but only of not nullable classes. The real superclass of all Kotlin classes is Any? (it is also a superclass of Any).

    The generic type T in your test function has no upper bound so it can be a nullable object Any?. The error is because you can't a Comparator<Any> when you need a Comparator<Any?>.

    So you can fix your example defining the T upper bound as Any:

    fun <T: Any> test() {
        //...
    }