Reputation: 319
This question follows the one in Cake pattern with overriding abstract type don't work with Upper Type Bounds. I want to override the abstract type in trait with <:
. The previous links gives the solution which consists in changing the order of linearization by writting this: Cake with S
in trait S. However, I added a control abstraction named control
in the following code. I want to call the method t
in it.
trait A {
def ping = println("ping")
}
trait Cake {
type T
}
trait S { this: Cake with S =>
type T <: A with S
def t: T
def s = println("test")
// def control(c: =>T): T = c // compile
// def control(c: =>T): T = c.s // does not compile
def control(c: =>T): T = c.t // does not compile
t.ping
t.s
}
But, this code results in a compilation error that I can't explain
found : S.this.T#T
required: S.this.T
def control(c: =>T): T = c.t
^
What is wrong ?
Upvotes: 0
Views: 118
Reputation: 4891
def control(c: =>T): T
Has return type S#T
. Clearly, c
has type T
as well. Hence, returning c
in:
def control(c: =>T): T = c
compiles, while returning c.s
does not compile because s
has return type of Unit
.
c.t
does not compile because it has return type of S#T#T
.
Thus, the following will compile:
def control(c: =>T): T#T = c.t
As the specifics behind everything that is happening here are a bit non-trivial in general, I suggest you google "type projection" and "path dependent types" for more information.
Essentially what is happening is c
has type T
, where T <: A with S
, so we know T
must have all of S
's members, one of which is defined as def t: T
. But this T
is not necessarily the same as our T
, so it does not conform when we call c.t
in your example. What we want is the T
of type T
(or equivalently, T
's T
, or the T
of our type member T
). Here T#T
indicates exactly what we want.
Upvotes: 1