Guide to Trait Linearisation in Scala

Sayan Chakraborty
Jan 17 · 3 min read

Hi, since you are here I am assuming you are working in Scala and you have been using a lot of mixins with overriden methods and now you don’t understand in which order your overriden methods are being called. Don’t worry, I’ll try my best to prevent that divorce/breakup that you are heading to right now.

What is Linearisation ?

Let’s say you have written something like this :

class X extends A with B with C with D

So what you’re basically saying here is that you want class X to extend (A with B with C with D) where A, B, C, D are traits. These traits might have inherited from each other forming an inheritance tree. Scala has to figure out a way to flatten the inheritance tree so that it knows exactly where to look for methods and data.

Let’s look at an example to understand the problem :

trait A {
def saysHello = "Hello from A"
}
trait B {
def saysHello = "Hello from B"
}
class Girl extends A with B {
override def saysHello = super.saysHello
}

On calling the method saysHello:

new Girl saysHello

(Yes, I have been watching a lot of New Girl lately).

Scala has to decide which method to invoke (dilemma of multiple inheritance). Scala makes this decision using a linearised graph (or a singly linked list) that it creates from the inheritance tree. This process is called Linearisation and this is what helps Scala take care of the multiple inheritance problem. Irrespective of multiple inheritance, Scala will create a linearised graph every time you extend something.

How is Linearisation achieved ?

I think this is best demonstrated with an example. Consider the following example :

How would the linearised graph look like for a call to hello method of Impl1 ? Let’s figure it out. Scala would scan the traits from left to right and resolve dependencies for each trait.

For A, the dependency would look like :

A -> Base -> AnyRef -> Any

For B, the dependency would be just :

B

You must be wondering why does B in this case not inherit from Base ?
The reason is that Base, AnyRef and Any are already inherited by A, therefore, B will not inherit them anymore.

While scanning traits from left to right, Scala also keeps track of the dependencies to make sure that the same dependency is not being included in the linearisation graph for further traits.

Now, the consolidated linearised graph would look like :

B -> A -> Base -> AnyRef -> Any

This is the inheritance hierarchy that class Impl1 inherits. Overall, your class hierarchy would look like :

Impl1 -> B -> A -> Base -> AnyRef -> Any

And a method call like new Impl1 hello would return you :

Impl1 -> B -> A -> Base

Now let’s figure out the linearised graph for Impl2 :

class Impl2 extends B with A

For B :

B -> Base -> AnyRef -> Any

For A it is just :

A

The consolidated linearised graph would look like :

A -> B -> Base -> AnyRef -> Any

And a call to hello of Impl2 would return you :

Impl2 -> A -> B -> Base

Now let’s figure out the linearised graph for Impl3 :

class Impl3 extends C with B with A

Resolving C:

C -> A -> Base -> AnyRef -> Any 

Resolving B :

B

A is already present so it will not be added again. The consolidated graph would look like :

B -> C -> A -> Base -> AnyRef -> Any

And a call to hello method of Impl3 would return you :

Impl3 -> B -> C -> A -> Base

Similarly for Impl4 :

class Impl3 extends A with B with C

Resolving A :

A -> Base -> AnyRef -> Any

Resolving B :

B

Resolving C :

C

The overall graph would look like :

C -> B -> A -> Base -> AnyRef -> Any

And a call to the hello method of Impl4 would return you :

Impl4 -> C -> B -> A -> Base

Conclusion

In a nutshell, Scala scans your traits from left to right and resolves all their dependencies one by one eliminating the ones that have already appeared before. Once, it has resolved every trait’s dependencies, it creates a linearised graph by starting from the bottom and moves all the way up (or right to left in this case).

I hope this post has been helpful for people who came here to understand how linearisation in Scala works. Thank you.

Sayan Chakraborty

Written by

Software Consultant @ThoughtWorks

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade