Artem Pelenitsyn
Artem Pelenitsyn

Reputation: 2578

Values of abstract member types

I'm trying to use this kind of code:

trait Outer {
  type Inner

  def f(x:Inner) : Void 
}

object test {
  def apply(o: Outer, i : Outer#Inner) : Void = 
    o.f(i)
}

I got an error in the last but one line:

type mismatch; found : i.type (with underlying type Outer#Inner) required: o.Inner

If I change apply's signature to

def apply(o: Outer, i : o.Inner) : Void

then I got an error:

illegal dependent method type

Is it possible to get this piece of code work?

Upvotes: 3

Views: 117

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170733

But imo o.Inner is much uglyier than Outer#Inner. Would you explain, what the point of use former instead of latter? The compiler can do only static checks so o.Inner should be equal o.type#Inner which should be (statically) equal to Outer#Inner. Am I missing something?

Here is the reason. Imagine you had

class Outer1 extends Outer {
  type Inner = Int

  def apply(i: Int) { ... }
}

class Outer2 extends Outer {
  type Inner = String

  def apply(i: Int) { ... }
}

Should test.apply(new Outer1, "abc") compile? Obviously not, since it'll call Outer1.apply(String), which doesn't exist. But then, test.apply(new Outer1, 1) can't compile either (otherwise you are back to path-dependent types) and there is no way to use this apply at all!

Upvotes: 1

Régis Jean-Gilles
Régis Jean-Gilles

Reputation: 32719

You can take advantage of method dependent types (see What are some compelling use cases for dependent method types? by example). This will require you to use 2 parameter lists:

trait Outer {
  type Inner
  def f(x:Inner): Unit 
}

object test {
  def apply( o: Outer )( i : o.Inner) { o.f(i) }
}

Upvotes: 5

Related Questions