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?
(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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With