I want to override abstract type in trait with <:
and not with =
(like answer here Scala Upper Bounds : value is not a member of type parameter).
I want to use cake pattern, but this doesn't work, i don't understand why ?
trait A {
def ping = println("ping")
}
trait Cake {
type T
}
trait S { this: Cake =>
type T = A
def t: T
t.ping
}
OK, this example run, but in my real use case i want to override type with <:
and not with =
.It seems impossible to access the t function, why ?
trait S { this: Cake =>
type T <: A
def t: T
t.ping
}
return an error value ping is not a member of S.this.T
It's a shortcoming of Scala's type system. When determining the members in a mixin, Scala uses two rules: First, concrete always overrides abstract. Second, If two members are both concrete, or both abstract, then the one that comes later in linearization order wins.
Furthermore, the self type of a trait
trait S { this: C => ... }
is implicitly augmented to
trait S { this: S with C => ... }
so that definitions in the trait S can be accessed within S. In your case, the trait S is seen as:
trait S { this: S with Cake =>
type T = A
def t: T
t.ping
}
Now, as long as T is concrete this is fine because it overrides the abstract T in Cake. But if T is abstract, the one in Cake cames later in the linearization order and wins. And that T does not have an upper bound, so no member ping. One way to fix this is to change the linearization order by writing:
trait S { this: Cake with S =>
type T <: A
def t: T
t.ping
}
It would be cleaner if Scala had a different rule that says that all constraints of abstract type members are merged in the mixin, instead of picking a single member according to linearization order. That's a change we want to consider in the future, but we need to be careful with backwards compatibility.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With