GDD
GDD

Reputation: 319

Overriding abstract type does not work with control abstraction

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

Answers (1)

Alex DiCarlo
Alex DiCarlo

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

Related Questions