Почему в этом коде Scala необходимо повышать приведение?

Это компилирует:

import scala.collection._

trait Foo[A, +This <: SortedSet[A] with SortedSetLike[A,This]]
extends SortedSetLike[A, This] { this: This =>

  def bar: This = (this: SortedSetLike[A,This]).empty

}

Но если upcast удален, он не скомпилируется:

import scala.collection._

trait Foo[A, +This <: SortedSet[A] with SortedSetLike[A,This]]
extends SortedSetLike[A, This] { this: This =>

  def bar: This = this.empty

}

Почему? Из предложения extends мы знаем, что Foo является SortedSetLike[A, This], поэтому приведение вверх, конечно, допустимо, но разве это не показывает, что компилятор допустил конфликтующее наследование?


person Robin Green    schedule 26.06.2015    source источник
comment
Я не знаю точных деталей этого случая, но это еще один пример ужасных вещей, которые могут произойти, потому что методы в подклассах могут иметь более конкретные типы возвращаемых значений, чем сигнатуры методов, которые они реализуют.   -  person Travis Brown    schedule 27.06.2015


Ответы (1)


Черта SortedSetLike наследует метод empty от SetLike.

/** The empty set of the same type as this set
* @return  an empty set of type `This`.
*/
def empty: This

Но SortedSet переопределяет метод пустой и имеет явный возвращаемый тип:

/** Needs to be overridden in subclasses. */
override def empty: SortedSet[A] = SortedSet.empty[A]

Поскольку вы укажете, что This является подклассом SortedSet, компилятор сначала найдет реализацию SortedSet пустой, который возвращает SortedSet. Компилятор не знает, как преобразовать результирующий SortedSet в ваш подкласс This.

Но если вы приведете к трейту SortedSetLike, компилятор найдет его пустой метод, который возвращает This.

person Chris P.    schedule 10.09.2015