Consider the following example of traits:
trait TextileEngineer extends Engineer {
override def nameIt = {println("TextileEngineer"); super.nameIt;}
}
trait FabricEngineer extends Engineer {
override def nameIt = {println("FabricEngineer"); super.nameIt;}
}
trait Engineer extends Person {
override def nameIt = {println("Engineer"); super.nameIt;}
}
trait ClothMaker extends Trader {
override def nameIt = {println("ClothMaker"); super.nameIt;}
}
trait Trader {
def nameIt = println("Trader");
}
trait Parent extends Person with Human {
override def nameIt = {println("Parent"); super.nameIt;}
}
trait Person extends Human {
override def nameIt = {println("Person"); super.nameIt;}
}
trait Human {
def nameIt = {println("Human");}
}
object Linear extends App {
val data = new TheSmiths {}
data.nameIt
}
trait TheSmiths extends FabricEngineer with TextileEngineer with ClothMaker with Parent {
override def nameIt: Unit = super[TextileEngineer].nameIt //-----------override:1
override def nameIt: Unit = super[FabricEngineer].nameIt //------------override:2
override def nameIt: Unit = super.nameIt //------------override:3
}
- when in the final trait - the override:1 is used - the output is -
TextileEngineer
FabricEngineer
Engineer
Person
Human
- but when override:2 is used - the answer is -
FabricEngineer
Engineer
Person
Human
- But when the override:3 is used - the answer is - Why is the hierarchy not followed upto the
Human
when the traitParent
is the part of other hierarchy?
Parent
ClothMaker
Trader
CodePudding user response:
The short answer:
Because Trader
does not call super
inside nameIt
:
trait Trader {
def nameIt = println("Trader");
}
The long answer:
Linearization begins with TheSmiths
itself, then checks every class or trait it inherits from, starting from the rightmost extended trait to the leftmost extended trait (or class if you extend one), but in a depth-first search manner.
So for example, your linearization of TheSmiths
is:
TheSmiths -> Parent -> Person -> Human -> ClothMaker -> Trader -> TextileEngineer ->
Engineer -> Person -> Human -> FabricEngineer -> Engineer -> Person -> Human
Now duplicates (which indicate a diamond problem) are eliminated leaving the last occurrence of every type in the list. So the actual linearization of TheSmiths
becomes:
TheSmiths -> Parent -> ClothMaker -> Trader -> TextileEngineer -> FabricEngineer ->
Engineer -> Person -> Human
This is the linearization that occurs when you instantiate TheSmiths
using new
.
Then, whenever you call
super
inside one of those classes, the invoked method is the next one up the chain. If all of the methods but the last one call super, the net result is stackable behavior.
This linearization also serves as a way of verifying the output of the 2 other examples you gave.