6

Edit: Thanks to Derek pointing out the critical part of the error message, I was able to extract the critical part a bit more and it seems to be about Existential Types. If I do understand §3.2.10 Existential Quantification over Values in the language reference correctly, then val m: Map[x.type#S, x.type#S] forSome { val x: T } is a shorthand for val m: Map[t#S, t#S] forSome { type t <: T with Singleton }. Yet in the code below they do behave differently.

trait Type {
  type S
}

class Concrete extends Type {
  type S = Double
}

trait BaseWorks {
  type T <: Type
  val m: t#S forSome { type t <: T with Singleton }
}

class Works extends BaseWorks {
  override type T = Concrete
  override val m = 0.0
}

trait BaseError {
  type T <: Type
  val m: x.type#S forSome { val x: T }
}

class Error extends BaseError {
  override type T = Concrete
  override val m = 0.0
}

Refining BaseWorks works, while refining BaseError leads to the error error: overriding value m in trait BaseError of type Error.this.x.S forSome { val x: => Error.this.T }; value m has incompatible type. Am I misinterpreting §3.2.10?

Original post: In the following piece of Scala code the compiler (2.9.0.1) produces an error saying that method f2 overrides nothing in Derived.

abstract trait Type {
  type T1
  type T2
  type P = (T1, T2)
}

class ConcreteType extends Type {
  type T1 = Double
  type T2 = Double
}

abstract class Base {
  type T <: Type
  type TP = T#P
  def f1(v: TP): TP
  def f2(v: T#P): T#P
  def f3(v: T#P): T#P
}

class Derived extends Base {
  override type T = ConcreteType
  override def f1(v: TP): TP = v
  override def f2(v: T#P): T#P = v
  override def f3(v: TP): TP = v
}

On the other hand, overriding the function f3 with the exact same signature as shown in the code works. I would expect that both functions behave in the same way. Why is this not the case?

1 Answers1

5

(FYI, I'm using 2.9.0.1)

I haven't been able to find the reason for this in the spec but the error message you get, at least, makes the ultimate reason clear. This is the key part:

(Note that (_5.T1, _5.T2) forSome { val _5: Base.this.T }
does not match
(_16.T1, _16.T2) forSome { val _16: Base#T }

Base.this.T is not equivalent to Base#T. The former is a path-dependent type based on the instance this where as the latter is a type projection that is not instance based.

This appears to be due to the order of type resolution. TP is resolved with respect to the evaluation of Base whereas T#P is resolved with respect to the evaluation of Derived.

If someone can point to the location in the spec that can explain this properly, I'd love to read it.

Derek Wyatt
  • 2,677
  • 13
  • 23
  • Hi Derek. Thanks for pointing out the key part. I was able to extract the critical part a bit more. I'll update the post above. – Mathias Körner Aug 12 '11 at 18:47