Cake pattern with overriding abstract type don't work with Upper Type Bounds
cake-pattern, dependency-injection, scala, traits
Solution
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.
Problem
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`