ScalaKnol: Understanding Traits as Stackable Modifications

Table of contents
Reading Time: 3 minutes

Traits can be used to modify the methods of a class. The way such modifications are carried out is such that they can stack modifications with each other.

Let us take an example. Say, there is a class called ImageProcessor which processes images. Now there are a few modifications required before the image is actually uploaded to your server. If you are using Facebook then for every image uploaded, it does a few things on the image which might include i) compressing the image ii) scaling that in various sizes iii) extracting a snapshot of the image of the video etc. It might do a ton of other things but let us keep it simple for now.

So lets see some code

So, ImageProcessor is the abstract class and ImageProcessorImpl is the concrete class which provides implementation. Calling a process on the implementation gives us the following result

Now, what if we want to add modifications to the base image processing, which would say cut a frame out of that image. We define a trait called FrameCutter which does the following

We are doing an abstract override here. Such a combination is only possible in traits. What we are doing here is that we are telling the compiler that we are defining a trait which would always be mixed with another trait or class which would provide the concrete implementation of process.

Let us define another trait which compresses the image which is uploaded to the server

Now, these 2 traits describe modifications. They modify the bahavior of the process method and they can be stacked to give stackable modifications. So, let us say we need an object that first “cuts a frame” and then “compresses the image” and then “does the base processing”. Such an object would be defined like

So, we mixed the traits with a concrete class which provides the definition of process. The interesting thing to note here is that with traits, super is dynamically bound on the basis of how the trait is mixed. When a method is called on a trait then the method is called on the trait which is further right in the mix. If this method calls super then it invokes this method on the trait on the left and so,on. In the above example, FrameCutter was the last trait (furthest to the right) which was mixed in. It is called and then the ImageCompressor and then the Concrete class.

Super for classes is always determined statically. Hence for the following code,

super for ImageProcessorImpl is always ImageProcessor.

Ok, coming back to our stackable modifications. What would you do if we need to compress the image first and then cut it? We would mix it the other way i.e.

So we get modifications in traits and we can stack them the way we want to get the desired results. The key things to remember are
i) Behavior of super in traits
ii) Declaring methods with abstract override in traits
iii) Keeping in mind the order of mixin.

Written by 

Vikas is the CEO and Co-Founder of Knoldus Inc. Knoldus does niche Reactive and Big Data product development on Scala, Spark, and Functional Java. Knoldus has a strong focus on software craftsmanship which ensures high-quality software development. It partners with the best in the industry like Lightbend (Scala Ecosystem), Databricks (Spark Ecosystem), Confluent (Kafka) and Datastax (Cassandra). Vikas has been working in the cutting edge tech industry for 20+ years. He was an ardent fan of Java with multiple high load enterprise systems to boast of till he met Scala. His current passions include utilizing the power of Scala, Akka and Play to make Reactive and Big Data systems for niche startups and enterprises who would like to change the way software is developed. To know more, send a mail to hello@knoldus.com or visit www.knoldus.com