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.
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() {
//...
}