Reputation: 155
I've been experimenting with generics lately and found a good instance where I could use them, however, I've become stuck and my searches haven't resulted in a solution, or I've misunderstood. See below code sample:
open class X()
class Y : X()
class Z : X()
abstract class A<T : X> {
lateinit var one: T
fun setup(
one: T
) {
this.one = one
}
}
class B<T : Y> : A<T>()
class C {
fun initB() {
B<Y>() // Works as intended
B<Z>() // Type argument is not within its bounds
B<X>() // Type argument is not within its bounds
}
}
I would like to have a situation whereby accessing one
from class B
type of one
is correctly inferred, so if I instantiate B
with type Z
then one
will be inferred also as type Z
. Unfortunately doing this how I thought was the correct way results in 'Type argument is not within its bounds
'. Any help would be greatly appreciated.
Upvotes: 1
Views: 1361
Reputation: 93872
B's type has to be a subtype of Y as you defined it B<T : Y>
, but neither X nor Z is a subtype of Y. X is a supertype of Y, and Z has no vertical connection to Y at all.
Even if they were subtypes, you couldn't do what you were hoping to. Since your class has a T
var, T
has to be invariant for it to work. Invariant means you cannot implicitly up- and down-cast the type of an instance of the class.
Consider how it would break if it allowed you to:
val bY: B<Y> = B<Y>()
val bX: B<X> = bY // not allowed because of invariance
// If it were allowed:
bX.one = X()
val y: Y = bY.one // ClassCastException: cannot cast X to Y
Upvotes: 4