2012-06-23 3 views
4

Voici un casse-tête de linéarisation des traits qui me cause des maux de tête. J'ai fondamentalement le type Node qui définit equals et hashCode à comparer à d'autres Node s. Et j'ai un type Selector qui peut envelopper un Node avec des données supplémentaires, et a donc ses propres equals et hashCode à comparer à d'autres Selector s.Linéarisation des traits gênants?

Maintenant, j'ai un type Standalone qui combine Node et Selector, mais je reçois incompatibles Linéarisation par rapport à equals et hashCode (?):

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

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

Maintenant, tout va bien (le hashCode plus spécifique 1 est appelé) quand je tends à partir soit Event ou Standalone:

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

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

Il est également très bien si je tiens à la fois dans cet ordre:

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

Mais il salit quand je fais ceci:

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

J'ai fait un petit diagramme .dot (mixins sont commandés de gauche à droite):

enter image description here

Donc, si je comprends bien linearisation rules, je devrais toujours finir avec le hashCode mis en œuvre par Selector. La seule explication à ce comportement serait qu'il y ait une sorte de chose gourmande/en profondeur en premier ...?

De plus, s'il y a une technique que je peux utiliser pour vous assurer que chaque fois Standalone est mélangé, il est assuré que Selector outrepasse Node (autres que la copie equals et hashCodeSelector-Standalone), qui serait très apprécié .

Ceci est avec Scala 2.9.2.

Répondre

4

Il est préférable d'aller à la Spec pour ce genre de chose. L'algorithme est décrit à 5.1.2 Class Linearization

En le paraphrasant, la linéarisation d'une classe C est C suivie de la linéarisation des objets qu'elle étend en commençant par l'élément le plus à droite. Ensuite, il y a la dernière étape de suppression des doublons dans la linéarisation, en ne gardant que les plus à droite.

Donc, dans votre exemple pour Compound1 (en ignorant ins construit comme 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
Putting ensemble:
L(Compound1) = Compound1 Event Selector Standalone Event Selector Node
Suppression des doublons:
Compound1 Standalone Event Selector Node

Pour Compound2, il finit par être:
Compound2 Standalone Node Event Selector


Quant à l'autre question, je pense que la meilleure façon serait de remplacer la méthode Standalone et appeler la méthode souhaitée dans la super-classe . En supposant que ce n'est pas ce que vous vouliez dire par "copier".

+0

_maintenant seulement le plus à droite _... ok, donc cela semble être le problème alors. Je suppose qu'il n'y a aucun moyen de ré-implémenter les méthodes dans 'Standalone' ... –

+0

' Standalone' vient avant 'Node' et' Selector' dans la linéarisation des deux objets afin que vous puissiez le remplacer ici. Cependant, tout cela me semble très fragile, vous feriez probablement mieux de le redessiner. – Kaito

Questions connexes