In our previous blog The Story of Trait – Part 2, we have discussed that traits can have implementation too and how they behave under the hood.
In this blog, we will discuss mixins one of the most charming features of traits.
Mixins are the wonderful concept of object-oriented programming. Sadly, some of the mainstream object-oriented programming languages like C++, Java, C#, have not provided mixins. But we can use mixins in languages like Groovy, Scala etc.
What are mixins?
In layman terms, suppose you go to an ice cream shop. You can have ice creams like vanilla, butterscotch etc. But you prefer to take vanilla flavour with chocolate topping with some peanuts. Chocolate toppings and peanuts are mixins. So you can get lots of mixins on top of your ice cream. And another person can enjoy same flavoured ice cream but with different mixins like strawberry and cherries on top of it. The point is you can have any number of mixins on top of it.
Here, Soft Serve chocolate is the example of mixin. So, traits give us the ability to add mixins to the class we have.
For example, we have a class Human which has a method listen,
We know that Dog is also the best friend of Human. So, we want another class Dog which has a method listen. But it will violate the DRY principle. We will go creating a trait Friend which will have listen method and abstract field name and will mix trait Friend into Human and Dog class.
If a class does not extend from other classes or traits use extends keyword. And if a class extends from class and traits. Use extends to class and with for traits. Here class Human and Dog mixes in Friend trait.
So, we can say the trait is also a behaviour that can be mixed or assimilated into a class hierarchy. Traits look similar to classes but have some differences. First, the mixed-in class has to implement the abstract variable and can override method declared. Second, trait constructor can not take parameters whereas class constructors can have.
Traits also provide the facility of selective mixins. We can also mix in traits selectively at an instance level. This will allow you to treat a specific instance of a class as a trait.
Cats are generally not good friends of Human so they don’t have listen method too. But if you have a special cat Tom which listens to you. We do want to treat some cats as a friend. It won’t be hard to make some cats friendly. What we can do is we can mix friend trait at the instance level.
So you can see, Tom is listening. So, in general, cats are not treated as friendly. We can take selected objects of cat and make them friendly. This is the ability to provide traits or mixin traits at an instance level.
Let’s see how it works under the hood:
After compiling above code, we will see Scala compiler creates three .class files for Sample i,e. Sample.class, Sample$$anon$1.class and Sample$delayedInit$body.class.
If you look at Sample$delayedInit$body.class using javap, you will notice,
Notice anonymous inner class extends from class Cat and implements Friend. Scala implements instance level traits using anonymous inner classes which extend from that particular class and implement the trait as well. So tom is an instance of the anonymous inner class created by Scala compiler.
We have seen how traits provide mixins and selective mixins as well. How selective mixins are handled at the bytecode level. In next blog The Story of Trait – Part 4, we will look how Scala solves the problem of multiple inheritence. Till then, Stays tuned 😉
Please feel free to suggest and comment.