Max
Max

Reputation: 155

Generics; Type argument is not within its bounds

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

Answers (1)

Tenfour04
Tenfour04

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

Related Questions