Как абстрактно расширить трейт, зависящий от пути: переопределить трейт?

Как указать для определенного включающего объекта трейт, зависящий от пути, что этот трейт должен поддерживать дополнительную функцию? override trait? Как вы относитесь к исходной черте, которую расширяет подчерта?

В частности, я хочу переопределить черту Delta в каждом объекте DeltaSet:

trait DeltaSet {
  type PertainsTo

  trait Delta {
    val pertainsTo: PertainsTo
  }
  . . .
}

По-английски это звучит так: «Каждое Delta в одном и том же DeltaSet должно относиться к одному и тому же типу вещей».

Объект DeltaSet должен иметь возможность добавлять дополнительные атрибуты к признаку Delta, например source здесь:

val deltaSet = new DeltaSet {
  override type PertainsTo = UnorderedPair[TestNode]

  override trait Delta /* extends DeltaSet.Delta?? */ {  // <-- THE MYSTERY
    val source: TestNode
  }
  . . .
}

На английском языке это звучит так: «Каждый Delta для deltaSet должен также указать источник».

Таким образом, классы Delta для использования с этим объектом DeltaSet должны переопределять атрибут source, например:

case class MakeLinkDelta(fromNode: TestNode, toNode: TestNode)
  extends deltaSet.Delta
{
  override val pertainsTo = new UnorderedPair(fromNode, toNode)
  override val source = fromNode
  . . .
}

и аналогично для BreakLinkDelta и других Deltas для deltaSet. (Каждый Delta для этого DeltaSet описывает изменение, которое необходимо внести в граф. Другие DeltaSet содержат изменения совершенно разных типов объектов.)

Я пробовал много вариантов, включая trait BaseDelta {...}; type DeltaT <: BaseDelta, и пока ни один из них не скомпилировался. Как вы «скажете» на Scala: «Только для этого DeltaSet я хочу потребовать, чтобы каждый Delta предоставлял атрибут source


person Ben Kovitz    schedule 05.07.2015    source источник


Ответы (2)


Это работает:

(1) Определите базу trait во включающем признаке и сделайте ее верхней границей для абстрактного type.

(2) Создайте объект-контейнер с оператором object, а не с оператором val.

(3) Поместите переопределение класса в object, определив вложенный trait с тем же именем, что и абстрактный type. Это определение должно расширять базу trait и не должно не содержать ключевое слово override.


Вот (1), закрывающий признак:

trait DeltaSet {
  type PertainsTo

  trait BaseDelta {
    val pertainsTo: PertainsTo
  }

  type Delta <: BaseDelta          // <-- Since this is now a type, we can override it...
  . . .
}

Вот (2) object, определяющий конкретное DeltaSet, и (3) переопределение класса, определяющее Delta:

object deltaSet extends DeltaSet {
  override type PertainsTo = UnorderedPair[TestNode]

  trait Delta extends BaseDelta {  // ...except we don't override, we just define a trait
    val source: TestNode           // with the same name as the abstract type.
  }
  . . .
}

Я предполагаю, что причина, по которой object компилируется, а val терпит неудачу, заключается в том, что val не определяет пространство имен, а нам нужно пространство имен, чтобы ссылаться на закрытый, переопределенный трейт Delta, когда мы подклассифицируем его здесь:

case class MakeLinkDelta(fromNode: TestNode, toNode: TestNode)
  extends deltaSet.Delta           // Since deltaSet is a namespace, the dot syntax can refer
{                                  // to the Delta trait inside it.
  override val pertainsTo = new UnorderedPair(fromNode, toNode)
  override val source = fromNode
  . . .
}

(Эта последняя часть не отличается от кода в вопросе.)

person Ben Kovitz    schedule 05.07.2015

Расширьте DeltaSet и его Delta, добавив атрибут source:

trait DeltaSetTN extends DeltaSet {
  override type PertainsTo = UnorderedPair[TestNode]
  trait DeltaTN extends Delta {
    val source: TestNode
  }
}

Затем:

class MakeLinkDelta(fromNode: TestNode, toNode: TestNode) extends DeltaSetTN {
  val delta = new DeltaTNImpl()
  class DeltaTNImpl extends DeltaTN {
    override val source = fromNode
    override val pertainsTo = new UnorderedPair[TestNode](fromNode, toNode)
  }
}

Вас может заинтересовать этот сообщение в блоге о внедрении зависимостей в Scala и шаблоне торта.

person bjfletcher    schedule 05.07.2015
comment
Можете ли вы объяснить соответствующий принцип работы здесь? «Вы не можете переопределить трейт, зависящий от пути, в анонимном классе»? «Вы нигде не можете переопределить черту, зависящую от пути»? «Каждый зависимый от пути (Delta) объект должен расширять свойство контейнера (DeltaSet)»? Я надеюсь, что последнее не является истинным принципом. - person Ben Kovitz; 06.07.2015
comment
Мы не можем переопределить черту. Для этого мы расширяем и переопределяем его члены. Не уверен, что понял ваш последний пункт. Черта не может оставаться чертой при создании экземпляра. - person bjfletcher; 06.07.2015
comment
Спасибо за то, что мы не можем переопределить черту». (Возможно, это могло бы войти в ответ.) Уточнение последнего пункта: в вашем решении класс Delta расширяет черту DeltaSet. Мне это кажется странным, как сказать, что чашка — это своего рода шкаф. Есть ли какой-то принцип Scala, который требует этого? - person Ben Kovitz; 06.07.2015
comment
Я заменю MakeLinkDelta на DeltaForLink в вопросе, так как «Сделать» может вызвать путаницу. - person Ben Kovitz; 06.07.2015
comment
Конечно, предлагаемые изменения. Можете ли вы уточнить, где в моем коде Delta расширяет DeltaSet? - person bjfletcher; 06.07.2015
comment
MakeLinkDelta extends DeltaSetTN. Я предполагаю (возможно, ошибочно), что предполагаемое значение (используя новое имя для класса Delta) DeltaForLink extends DeltaSetForTestNodes. - person Ben Kovitz; 06.07.2015
comment
Кстати, я только что нашел рабочее решение, которым я вполне доволен. Он использует «вы не можете переопределить черту». Я опубликую это в другом ответе через пару минут. Однако я не совсем понимаю причины этого, поэтому, вероятно, не приму свой собственный ответ! - person Ben Kovitz; 06.07.2015
comment
С нетерпением жду этого. :) - person bjfletcher; 06.07.2015
comment
Вы знаете, вы можете отредактировать мой ответ с альтернативными именами. Я одобрю это. :) - person bjfletcher; 06.07.2015
comment
Превосходно. :) Думаю, я вернусь к MakeLinkDelta и упомяну контрастный BreakLinkDelta. Это должно прояснить, что может быть много Delta классов для одного DeltaSet (и требуется меньше редактирования). - person Ben Kovitz; 06.07.2015