'Kotlin generics with subtypes?
I can't wrap my head around why arent subtypes working with Kotlin generics.
Assume the following simple scenario
class Student : Person()
open class Person
This works
fun personOrStudent : Person{
return Student()
}
But this doesnt
fun <Item:Person> personOrStudent() : Item {
return Student()
}
I dont understand why. Isn't the return type Item , typed as a subtype of Person ? . I believe the syntax clearly communicates that Item would be a subtype of Person .
But I get a compile time error saying expected was Person , not a student.
Does this have something to do with covariance / contravariance?
Solution 1:[1]
By defining a function as parameterized we basically mean that we don't know the exact type of Item and that it depends on the call site. Student may be a valid return value from this function, but it may be not.
Consider this example:
class NotAStudent : Person()
personOrStudent<NotAStudent>()
We expect that the function returns NotAStudent, but implementation returned Student. This is why it can't compile.
In other words: <Item: Person> doesn't mean that Item is just any Person. It means Item is a very specific subtype of Person, but we don't know which one.
Solution 2:[2]
A different way of explaining it in case it helps:
The difference is that with generics, the type that the generic represents is defined in the code that calls it. Your generic function doesn't return a Person. It returns whatever specific type the caller asks for. <T: Person> means the caller is restricted to asking for types that are Persons or subtypes of Persons.
open class Person
class Student : Person()
class Teacher: Person()
//...
val teacher = personOrStudent<Teacher>() // The caller is asking for a Teacher.
If they ask for a Teacher, a Student would be an invalid response.
In real-world application, I don't think there would ever be a reason to write a generic function like this, where the generic type is used solely as a return type and not by the parameters, because there's no way to determine/use the requested type if it isn't related to any of the function inputs. With reified types, it is possible, though, because the reified type is itself an input.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | broot |
| Solution 2 | Tenfour04 |
