Back2Basics: The Story of Trait – Part 3


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.

 

McDonalds India Desert

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,

scala> class Human(val name: String){
| def listen() = println(s"i am $name, listening...")
| }
defined class Human

scala> val mahesh = new Human("Mahesh")
mahesh: Human = Human@51a9ad5e

scala> mahesh.listen
i am Mahesh, listening... 

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.

scala> trait Friend{
| val name: String
| def listen = println(s"i am $name, listening...")
| }
defined trait Friend

scala> class Human(val name: String) extends Friend
defined class Human

scala> val mahesh = new Human("Mahesh")
mahesh: Human = Human@cdc3aae

scala> mahesh.listen
i am Mahesh, listening...

scala> class Animal
defined class Animal

scala> class Dog(val name: String) extends Animal with Friend
defined class Dog

scala> val scooby = new Dog("Scooby")
scooby: Dog = Dog@173b9122

scala> scooby.listen
i am Scooby, listening... 

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.

For example,

scala> class Cat(val name: String) extends Animal
defined class Cat 

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.

scala> val tom = new Cat("Tom") with Friend
tom: Cat with Friend = $anon$1@17d2ed1b

scala> tom.listen
I am Tom, listening... 

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,

javap -c Sample\$\$anon\$1.class
Compiled from "Sample.scala"
public final class Sample$$anon$1 extends Cat implements Friend {
public void listen();
Code:
0: aload_0
1: invokestatic #16 // Method Friend$class.listen:(LFriend;)V
4: return

public Sample$$anon$1();
Code:
0: aload_0
1: ldc #21 // String Tom
3: invokespecial #24 // Method Cat."":(Ljava/lang/String;)V
6: aload_0
7: invokestatic #27 // Method Friend$class.$init$:(LFriend;)V
10: return
}

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, we will look how Scala solves the problem of multiple inheritence. Till then, Stays tuned 😉

Please feel free to suggest and comment.

References:

Pragmatic Scala


knoldus-advt-sticker


About Mahesh Chand

Software Craftsman + Pragmatic Programmer + Explorer + Foodie + Movie Buff
This entry was posted in Scala and tagged , , , , , , , , , . Bookmark the permalink.

4 Responses to Back2Basics: The Story of Trait – Part 3

  1. Anurag Srivastava says:

    Reblogged this on Anurag Srivastava.

  2. Mahesh Chand says:

    Reblogged this on Agile Development and commented:
    Back2Basics: The Story of Trait – Part 3

  3. Pingback: Back2Basics: The Story of Trait – Part 2 | Knoldus

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s