https://kotlinlang.org logo
#getting-started
Title
# getting-started
p

poohbar

08/12/2022, 3:28 AM
Still learning about generics. In this example I would expect this to work, because I feel like
Animal<Int>
fits into
Animal<Any?>
. What am I missing?
Copy code
open class Animal<T>
class Dog: Animal<Int>()
val x : Animal<Any?> = Dog() // error at the constructor call
j

Joffrey

08/12/2022, 4:05 AM
By default, generics are invariant, which means there is no subtyping relations between different
Animal<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
p

poohbar

08/12/2022, 4:06 AM
Copy code
open class Animal<out T>
class Dog: Animal<Int>()
val x : Animal<Any?> = Dog() // works
i think i get it.. it is restrictive in some cases where i want to just “escape” Kotlin’s type system and go fully dynamic.. something like using
List
in Java. I don’t think it’s possible in Kotlin 🤔
j

Jacob

08/12/2022, 4:08 AM
What does an animal do with Ts? Do they have a method that returns them? then it makes sense that a dog is an animal<any> since it returns Ints which are techincally also Anys Do animals eat Ts? (ie have functions that take T as an arg) Than a dog is not an animal <any> since it doesn't eat anything, dogs only eat ints
You can go fully Dynamic just like java!
Copy code
open class Animal
class Dog: Animal()
val x : Animal = Dog() // works
😆
p

poohbar

08/12/2022, 4:12 AM
i know i know.. in most cases the generics are very helpful which is why i dont want to just remove them
j

Joffrey

08/12/2022, 4:28 AM
Kotlin doesn't have Java's raw types (which are pretty bad) but maybe you are looking for the syntax
Animal<*>
e

ephemient

08/12/2022, 4:56 AM
List<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)
v

Vampire

08/12/2022, 9:39 AM
Java also just allows raw types for backwards compatibility. Any code that uses them intentionally should be considered broken and wrong.
2
j

Joffrey

08/12/2022, 3:55 PM
Any code that uses them intentionally should be considered broken and wrong
We 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"
v

Vampire

08/12/2022, 3:59 PM
Most codebases probably have those 😄 Doesn't make it better though 🙈
j

Jacob

08/12/2022, 4:04 PM
On the topic of fooling the compiler, take a look at how mockito-kotlin can create instances of anything! https://github.com/mockito/mockito-kotlin/blob/37bbae48634d879640a754a1b122db99f0b[…]n/src/main/kotlin/org/mockito/kotlin/internal/CreateInstance.kt
😆 1
e

ephemient

08/12/2022, 5:03 PM
I'm not sure I'd call Kotlin's star projection a raw type - it doesn't automatically cast into the generic type, and it exposes a
<?>
signature to Java
j

Joffrey

08/12/2022, 5:05 PM
I don't believe anyone called the Kotlin star-projection a raw type. What are you referring to?
e

ephemient

08/12/2022, 5:12 PM
oh I misread Björn's reply
v

Vampire

08/12/2022, 7:21 PM
Definitely, didn't intend to imply they are similar. 🙂
5 Views