搞砸了特质线性化?

时间:2012-06-23 18:46:55

标签: scala multiple-inheritance traits linearization

这是一个引起头痛的特质线性益智游戏。我基本上输入Node,定义equalshashCode与其他Node进行比较。我有Selector类型可以包含Node以及额外数据,因此有自己的equalshashCode与其他Selector进行比较第

现在我有一个Standalone类型,它结合了NodeSelector,但我对equalshashCode的线性化不一致(?):

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

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

当我从EventStandalone延伸时,现在一切正常(调用更具体的hashCode 1):

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图表(mixins从左到右排序):

enter image description here

因此,如果我正确理解linearisation rules,我应该始终使用hashCode实施的Selector。对这种行为的唯一解释是,存在某种贪婪/深度优先的事情......?

此外,如果有一种技术我可以用来确保在Standalone混入时,确保Selector否决Node(除了复制equalshashCodeSelector)和Standalone,我将非常感激。

这是Scala 2.9.2。

1 个答案:

答案 0 :(得分: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 }  

假设这不是“复制”的意思。