Trait Linearization in Scala

Trait what?

Trait linearization is the process in Scala that kicks in when you mixin traits in your class. The subject might look intimidating at first, but the process is actually quite simple. I expect that you already know what traits are and what you can do with them. This blog will focus on the trait linearization process.

Why do we need it?

In some languages there exists a way to inherit from multiple classes. In scala this is not possible, but it is possible to mixin multiple traits which feels a bit like multiple inheritance. Multiple inheritance can lead to the diamond problem(1). This is the problem where a class extends two other classes and implementations collide. As you can see in the diagram below, the inheritance looks like a diamond and both classes (TwoLegged and FourLegged) override the legs method. The question to solve is what the implementation of legs will be.

Linearization

Scala linearization is a deterministic process that puts all traits in a linear inheritance hierarchy. By doing that we can solve the diamond problem, because we now know what the direct parent of the Beast class will be. Remember that the syntax to mixin traits is as follows: class A extends B with C with D. The rules for this process are as follows:

Start at the first extended class or trait and write that complete hierarchy down. We will call this the linearized hierarchy

Take the next trait and write this hierarchy down

now remove all classes/traits from this hierarchy which are already in the linearized hierarchy

add the remaining traits to the bottom of the linearized hierarchy to create the new linearized hierarchy

repeat step 2 for every trait.

Place the class itself as the last type extending the linearized hierarchy

Example

Without the Linearization process it would be unclear where the super.legs resolves to. Because of the linearization process, the compiler determines that super points to FourLegged. Let’s write this down by applying the rules mentioned above:

Start at the first extended class or trait and write that complete hierarchy down. The first trait is TwoLegged, so this leads to:
TwoLegged -> AnyRef -> Any

Take the next trait and write this hierarchy down. The next trait is FourLegged and the hierarchy is:
FourLegged -> AnyRef -> Any

now remove all classes/traits from this hierarchy which are already in the linearized hierarchy. This removes AnyRef and Any, so we are left with:
FourLegged

add the remaining traits to the bottom of the linearized hierarchy to create the new linearized hierarchy
FourLegged -> TwoLegged -> AnyRef -> Any

repeat step 2 for every trait. There are no more traits, so we are done.

Place the class itself as the last type extending the linearized hierarchy
Beast -> FourLegged -> TwoLegged -> AnyRef -> Any

The graphical representation looks like the picture below:

This hierarchy clearly shows that calling super from Beast will resolve to the FourLegged trait and thus the value of legs will be 4.

Complex Example: order shuffling

In most cases the trait linearization process is straightforward. If you look at the hierarchy and then look at the order of trait mixin, there is a clear match in the order. Usually there is no need to play all the rules, just looking at the order of mixin is enough. Calling super from the class will point to the last trait that was mixed in. But be careful, this will not always be the case. Let’s look at a more complex example:

Let’s try to find out what the linearized hierarchy is for class D. As before we will apply the linearization rules one by one.

Start at the first extended class or trait and write that complete hierarchy down. The first trait is FourLegged, so this leads to:
FourLegged -> Base -> AnyRef -> Any

Take the next trait and write this hierarchy down. The next trait is SixLegged and the hierarchy is:
SixLegged -> TwoLegged -> Base -> AnyRef -> Any

now remove all classes/traits from this hierarchy which are already in the linearized hierarchy. This removes AnyRef and Any, so we are left with:
SixLegged -> TwoLegged

add the remaining traits to the bottom of the linearized hierarchy to create the new linearized hierarchy
SixLegged -> TwoLegged -> FourLegged -> Base -> AnyRef -> Any

repeat step 2 for every trait. The next trait is TwoLegged and the hierarchy is:
TwoLegged -> Base -> AnyRef -> Any

now remove all classes/traits from this hierarchy which are already in the linearized hierarchy. This removes AnyRef and Any, so we are left with:
<<nothing>>

add the remaining traits to the bottom of the linearized hierarchy to create the new linearized hierarchy Because there is nothing to add it will stay the same:
SixLegged -> TwoLegged -> FourLegged -> Base -> AnyRef -> Any

repeat step 2 for every trait. There are no more traits, so we are done.

We end up with the linearized structure as shown below. Now that we have this linearized structure we can answer what the first supertype of D is and we no longer have the diamond problem.

Conclusion

The trait linearization might look intimidating at first, but as you have seen above, it consists of a few simple rules that you can apply yourself. It is good to be aware of this process. In daily life you don’t need to apply this rules that often. Also, placing println in the body of the traits that are mixed in will show you in what order the traits are executed and thus the hierarchy.

Delen:

Gerelateerd

My goal is to build systems that last! A system that will put a smile on the face of people using it and the people paying for it. In my mind the Typesafe Reactive Platform (Scala, Akka, Play, etc.) will be a big game changer in the coming years. It is giving a boost to Reactive programming. Together with DDD (Domain Driven Design) and CQRS (Command Query Responsibility Segregation) we will be able to implement all business requirements in a way that fits the rapid changing world. Helping the business to realize their needs is what it is all about. I have great interest in software languages and technologies and how to use them to help the business in new and better ways.