2012-06-23 2 views
4

Вот головоломка с линеаризацией признаков, которая вызывает у меня головные боли. У меня есть тип Node, который определяет equals и hashCode для сравнения с другими Node s. И у меня есть тип Selector, который может обернуть Node вместе с дополнительными данными и, таким образом, имеет свои equals и hashCode для сравнения с другими Selector s.Перевернутая линеаризация признаков?

Теперь у меня есть Standalone типа, который сочетает в себе Node и Selector, но я получаю несовместимую линеаризацию по отношению к equals и hashCode (?):

trait Selector { override def hashCode = 1 } 
trait Event extends Selector 

trait Node { override def hashCode = 2 } 
trait Standalone extends Node with Event 

Теперь все в порядке (более конкретные хэш-код 1 называются), когда я простираться от любой Event или Standalone:

object Single1 extends Event 
Single1.hashCode // 1 -- ok 

object Single2 extends Standalone 
Single2.hashCode // 1 -- ok 

это также хорошо, если я простираться от обоих в следующем порядке:

object Compound1 extends Standalone with Event 
Compound1.hashCode // 1 -- Ok 

Но это путает, когда я делаю это:

object Compound2 extends Event with Standalone 
Compound2.hashCode // 2 -- no!!!!!!!! 

Я сделал небольшую диаграмму .dot (Примеси упорядочены слева направо):

enter image description here

Итак, если я правильно понимаю linearisation rules, я должен всегда заканчивать hashCode, реализованный Selector. Единственное объяснение этого поведения было бы в том, что есть какая-то жадная/глубина первой вещи ...?

Кроме того, если есть техника, которую я могу использовать, чтобы убедиться, что всякий раз, когда Standalone смешивается, гарантируется, что Selector отменяет Node (кроме копирования equals и hashCode от Selector до Standalone), это было бы очень признателен ,

Это с Scala 2.9.2.

ответ

4

Лучше всего пойти в Spec для такого рода вещей. Алгоритм описан в 5.1.2 Class Linearization

Перефразируя его, Линеаризация класса C является C, за которой следует Линеаризация вещей, которые она расширяет, начиная с самого правого элемента. Затем есть заключительный этап удаления дубликатов в Линеаризации, сохраняя только самые правые.

Таким образом, в вашем примере для Compound1 (игнорируя встроенные модули, такие как AnyRef):
L(Compound1) = Compound1 + L(Event) + L(Standalone)
L(Event) = Event + L(Selector)
L(Selector) = Selector
L(Standalone) = Standalone + L(Event) + L(Node)
L(Node) = Node
Собирая вместе:
L(Compound1) = Compound1 Event Selector Standalone Event Selector Node
Удаление дубликатов:
Compound1 Standalone Event Selector Node

Для Compound2 он заканчивает тем, что:
Compound2 Standalone Node Event Selector


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

trait Standalone extends Node with Event { override def hashCode = super[Event].hashCode } 

Предполагая, что это не то, что вы имели в виду под «копированием».

+0

_ только один самый правый _... ok, так что, похоже, проблема тогда. Я думаю, что нет способа перепрограммировать методы таким образом в 'Standalone' ... –

+0

' Standalone' приходит перед 'Node' и' Selector' в линеаризации обоих объектов, чтобы вы могли переопределить его там. Однако все это кажется мне очень хрупким, вам, вероятно, лучше перепроектировать его. – Kaito

Смежные вопросы