Правила смешивания одной и той же черты несколько раз - PullRequest
2 голосов
/ 13 августа 2011

Я пытался написать какой-то кусок абстрактного кода, который усложнял его шаг за шагом. И он сломался на одном из этих шагов.

1-й шаг, правильный

trait Base
trait C1 extends Base

trait Abst extends Base
trait Conc extends Abst with C1

2-й шаг, правильный

object BaseHolder {
  trait Data
}

object C1Holder {
  trait Data extends BaseHolder.Data
}

trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data

3-й шаг, ошибка с ошибкой

trait BaseHolder {
  trait Data
}
object BaseHolder extends BaseHolder

trait C1Holder extends BaseHolder {
  trait Data extends super.Data
}
object C1Holder extends C1Holder

trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data

У меня ошибка: незаконное наследование; trait Con наследует различные типы экземпляров trait Data

Что означает эта ошибка и есть ли способ ее обойти?

Ответы [ 2 ]

6 голосов
/ 13 августа 2011

Полное сообщение об ошибке

[error]  trait Conc inherits different type instances of trait Data:
[error] C1Holder.Data and BaseHolder.Data
[error] trait Conc extends Abst with C1Holder.Data
[error]       ^
[error] one error found

Это говорит о том, что (object BaseHolder).Data не согласуется с (object C1Holder).Data, поскольку, хотя последний соответствует (trait BaseHolder)#Data, это менее специфично, чем trait Data в единственном экземпляре object BaseHolder.

Редактировать . Обратите внимание, что типы и значения находятся в разных пространствах имен, поэтому само имя BaseHolder неоднозначно, оно может относиться либо к признаку объекта. Тем не менее, при ссылке на тип, "." или символ "#" устраняет неоднозначность:

  1. T#Data всегда означает элемент типа Data в типе T. Например, BaseHolder#Data будет означать черту BaseHolder.

  2. x.Data всегда означает элемент типа Data в объекте x. Например, BaseHolder.Data будет относиться к одноэлементному объекту BaseHolder.

Обратите внимание, что два экземпляра x и y из trait BaseHolder будут иметь разные типы x.Data и y.Data; так работают зависимые от пути типы. Также обратите внимание, что object BaseHolder extends BaseHolder - это только один конкретный экземпляр trait BaseHolder.

Чтобы ваш код компилировался, убедитесь, что (trait C1Holder)#Data действительно соответствует (object BaseHolder).Data

trait BaseHolder {
  trait Data
}
object BaseHolder extends BaseHolder

trait C1Holder extends BaseHolder {
  trait Data extends BaseHolder.Data // Here BaseHolder refers to singleton object
}
object C1Holder extends C1Holder

trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data

В этом примере черты не так важны, так что вы можете просто пойти с

object BaseHolder {
  trait Data
}

object C1Holder {
  trait Data extends BaseHolder.Data
}

trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data
2 голосов
/ 13 августа 2011

Вы рассматриваете внешние черты как простые контейнеры для своих внутренних черт, почти как если бы вы относились к пакетам. Однако внутренние классы и черты имеют более сложную связь со своими родительскими классами.

Внутренние классы и признаки всегда связаны с экземпляром родительского класса. Невозможно создать внутренний класс без родительского экземпляра. На практике внутренние классы имеют скрытую ссылку, которая указывает на экземпляр родительского класса.

В вашем случае признак Data связан с объектом BaseHolder. Затем черта Abst расширяет BaseHolder.Data, поэтому он также связан с объектом BaseHolder. Это означает, что Abst будет ссылаться на объект BaseHolder как на своего родителя.

С другой стороны, C1Holder.Data ссылается на C1Holder как на своего родителя. Поэтому, когда вы определяете Conc, он должен ссылаться как BaseHolder и C1Holder как родительский. Но внутренняя черта может иметь только ОДНОГО родителя. Отсюда и ошибка.

...