Переопределение функций с параметрами, зависящими от пути - PullRequest
6 голосов
/ 11 августа 2011

Редактировать : Благодаря тому, что Дерек указал на критическую часть сообщения об ошибке, я смог извлечь критическую часть немного больше, и, похоже, она касается экзистенциальных типов. Если я правильно понимаю §3.2.10 Экзистенциальное количественное определение значений в справочнике по языку, то val m: Map[x.type#S, x.type#S] forSome { val x: T } является сокращением для val m: Map[t#S, t#S] forSome { type t <: T with Singleton }. Однако в приведенном ниже коде они ведут себя по-разному.

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
}

Рафинирование BaseWorks работает, а рафинирование BaseError приводит к ошибке error: overriding value m in trait BaseError of type Error.this.x.S forSome { val x: => Error.this.T }; value m has incompatible type. Я неправильно истолковываю §3.2.10?

Исходное сообщение : В следующем фрагменте кода Scala компилятор (2.9.0.1) выдает ошибку, сообщающую, что метод f2 ничего не переопределяет в 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
}

С другой стороны, переопределение функции f3 с помощью точно такой же сигнатуры , как показано в коде, работает. Я ожидаю, что обе функции ведут себя одинаково. Почему это не так?

1 Ответ

5 голосов
/ 11 августа 2011

(к вашему сведению, я использую 2.9.0.1)

Мне не удалось найти причину этого в спецификации, но полученное вами сообщение об ошибке, по крайней мере, проясняет окончательную причину. Это ключевая часть:

(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 не эквивалентно Base#T. Первый является зависимым от пути типом, основанным на экземпляре this, где последний является проекцией типа, которая не основана на экземпляре.

Похоже, это связано с порядком разрешения типов. TP разрешается в отношении оценки Base, тогда как T#P разрешается в отношении оценки Derived.

Если кто-то может указать на местоположение в спецификации, которое может объяснить это должным образом, я хотел бы прочитать его.

...