poohbar
08/12/2022, 3:28 AMAnimal<Int>
fits into Animal<Any?>
. What am I missing?
open class Animal<T>
class Dog: Animal<Int>()
val x : Animal<Any?> = Dog() // error at the constructor call
Joffrey
08/12/2022, 4:05 AMAnimal<T>
types even if there is a subtype relation between the T
inside. So what you're seeing is expected.
If you want Animal<Int>
to be a subtype of Animal<Any?>
, you need to make Animal<T>
covariant in T
. This is done by adding the keyword out
in front of T
poohbar
08/12/2022, 4:06 AMopen class Animal<out T>
class Dog: Animal<Int>()
val x : Animal<Any?> = Dog() // works
List
in Java. I don’t think it’s possible in Kotlin 🤔Jacob
08/12/2022, 4:08 AMopen class Animal
class Dog: Animal()
val x : Animal = Dog() // works
😆poohbar
08/12/2022, 4:12 AMJoffrey
08/12/2022, 4:28 AMAnimal<*>
ephemient
08/12/2022, 4:56 AMList<out E>
is how it's declared in Kotlin, because an unmodifiable list is covariant. Java's List<E>
is mutable thus the only reasonable behavior for the generic is invariant. (Kotlin does the same with MutableList<E>
.) Java treats arrays as covariant for historical reasons, but that's very broken (see https://docs.oracle.com/javase/8/docs/api/java/lang/ArrayStoreException.html)Vampire
08/12/2022, 9:39 AMJoffrey
08/12/2022, 3:55 PMAny code that uses them intentionally should be considered broken and wrongWe should make a poster or T-shirt out of this 😄 You should see some of the code I found in my previous company... full of raw types, and generics were used in ways that were just here to fool the compiler to make it "at least compile"
Vampire
08/12/2022, 3:59 PMJacob
08/12/2022, 4:04 PMephemient
08/12/2022, 5:03 PM<?>
signature to JavaJoffrey
08/12/2022, 5:05 PMephemient
08/12/2022, 5:12 PMVampire
08/12/2022, 7:21 PM