Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding functions with path-dependent type parameters

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?

like image 427
Mathias Körner Avatar asked Aug 11 '11 12:08

Mathias Körner


1 Answers

(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.

like image 194
Derek Wyatt Avatar answered Sep 18 '22 12:09

Derek Wyatt