In case of stackable modification, Scala arranges classes and traits in a linear order to determine method call hierarchy, which is known as linearization. The linearization rule is used only for those methods that involve method invocation via super()
. Let's consider this by an example:
class Shape {
def paint (shape: String): Unit = {
println(shape)
}
}
trait Color extends Shape {
abstract override def paint (shape : String) {
super.paint(shape + "Color ")
}
}
trait Blue extends Color {
abstract override def paint (shape : String) {
super.paint(shape + "with Blue ")
}
}
trait Border extends Shape {
abstract override def paint (shape : String) {
super.paint(shape + "Border ")
}
}
trait Dotted extends Border {
abstract override def paint (shape : String) {
super.paint(shape + "with Dotted ")
}
}
class MyShape extends Shape with Dotted with Blue {
override def paint (shape : String) {
super.paint(shape)
}
}
Linearization happens from back to front. In this case,
First Shape
will be linearized, which looks like:
Shape -> AnyRef -> Any
Then Dotted
is linearized:
Dotted -> Border -> Shape -> AnyRef -> Any
Next in line is Blue
. Normally Blue
's linearization will be:
Blue -> Color -> Shape -> AnyRef -> Any
because, in MyShape
's linearization until now (Step 2), Shape -> AnyRef -> Any
has already appeared. Hence, it is ignored. Thus, the Blue
linearization will be:
Blue -> Color -> Dotted -> Border -> Shape -> AnyRef -> Any
Finally, Circle
will be added and final linearization order will be:
Circle -> Blue -> Color -> Dotted -> Border -> Shape -> AnyRef -> Any
This linearization order decides invocation order of methods when super
is used in any class or trait. The first method implementation from the right is invoked, in the linearization order. If new MyShape().paint("Circle ")
is executed, it will print:
Circle with Blue Color with Dotted Border
More information on linearization can be found here.