Overriding functions with path-dependent type parameters

Change Thanks to Derek pointing to the critical part of the error message, I was able to extract the critical part a little more, and it looks like Existential types. If I understand correctly Β§3.2.10 Existential quantification over values ​​in a language rule, then val m: Map[x.type#S, x.type#S] forSome { val x: T } is short for val m: Map[t#S, t#S] forSome { type t <: T with Singleton } . However, in the code below, they 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 } 

Clearing BaseWorks works, and refining BaseError results in an error: overriding value m in trait BaseError of type Error.this.xS forSome { val x: => Error.this.T }; value m has incompatible type error: overriding value m in trait BaseError of type Error.this.xS forSome { val x: => Error.this.T }; value m has incompatible type . Am I misinterpreting Β§3.2.10?

Original post . In the following Scala code snippet, the compiler (2.9.0.1) generates an error saying that the f2 method does not undo anything 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 same signature as in the code works. I would expect both functions to behave the same. Why is this not so?

+6
source share
1 answer

(FYI, I am using 2.9.0.1)

I could not find the reason for this in the specification, 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 not equivalent to Base#T The former is a path-dependent type based on the this instance, where the latter is a projection of a non-instance-based type.

This is apparently related to the type resolution order. TP resolved with respect to Base , while T#P resolved with respect to Derived .

If someone can point to a place in the specification that can explain it correctly, I would love to read it.

+5
source

Source: https://habr.com/ru/post/894823/


All Articles