Back2Basics: The Story of Trait – Part 2


In our previous blog The Story of Trait – Part 1, we have discussed how traits are the just regular interfaces at the very basic form. In this blog, we will explore about traits can have method implementation too.

We will continue with our previous example and modify it and see how trait behaves in different scenarios.

Here we have implemented two method and other method is abstract in trait Animal and class Cat will extend it and give an implementation of abstract method comeToMaster. Let’s see how trait looks now under the hood.

If you take a trait with an implementation in it, it quickly becomes two things instead of one i.e an interface and an abstract class as well.

After compiling Sample.scala, use ls for .class files. And you will notice there will be two class files for Animal i.e  Animal.class, Animal$class.class.

If you take a look at them, Animal class will have an interface and Animal$class will have abstract base class. Let see first Animal.class, that should be an interface.

javap -c Animal.class
Compiled from "Sample.scala"
public abstract class Animal$class {
  public static void speak(Animal);
    Code:
       0: getstatic     #13                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       3: ldc           #15                 // String speaking..
       5: invokevirtual #19                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
       8: return

  public static void walk(Animal);
    Code:
       0: getstatic     #13                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       3: ldc           #24                 // String walking fastly..
       5: invokevirtual #19                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
       8: return

  public static void $init$(Animal);
    Code:
       0: return
}

Oh! , wait a minute, this does not show the interface, it is an abstract class. And if you see the Animal$class it will show the same bytecode as above. What exactly is happening?

Let’s dig deeper, we are being fooled by the tool. Let’s remove the Animal$class.class and now we are having only Animal.class.

javap -c Animal.class
Compiled from "Sample.scala"
public interface Animal {
  public abstract void speak();

  public abstract void walk();

  public abstract void comeToMaster();
}

Now you can see how the tool is fooling us. In Animal.class file, there is an interface. And All methods become abstract in interface i.e speak, walk, comeToMaster. We know that speak and walk have already implemented and the only comeToMaster is truly abstract in a trait.

What exactly happens at the bytecode level?

We can think about it slightly differently, we can provide our implemented method in abstract AnimalClass. In other words, when we give the implementation in a trait.

What Scala does under the hood, it moves an implementation to an abstract base class and keeps the trait as an interface all the way.

Let’ see the bytecode of Cat class,

Compiled from "Sample.scala"
public class Cat implements Animal {
public void walk();
Code:
0: aload_0
1: invokestatic #17 // Method Animal$class.walk:(LAnimal;)V
4: return

public void speak();
Code:
0: getstatic #26 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #28 // String meow....
5: invokevirtual #32 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return

public void comeToMaster();
Code:
0: getstatic #26 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #35 // String catch me if you can..
5: invokevirtual #32 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return

public Cat();
Code:
0: aload_0
1: invokespecial #38 // Method java/lang/Object."":()V
4: aload_0
5: invokestatic #41 // Method Animal$class.$init$:(LAnimal;)V
8: return
}

Notice, Cat class implements the Animal trait. However, it does implement the walk method. walk method makes an invokestatic call to walk method of abstract class Animal$class. Since we have overridden method speak in Cat, so it won’t make an invokestatic call to an abstract class.

So, we saw how trait behaves when it has an implemented methods also and how things work under the hood. In our next blog The Story of Trait – Part 3, we will see the mixin of traits. Till then Stay tuned 🙂

Please feel free to suggest and comment.

References:

Scala CookBook


knoldus-advt-sticker


About Mahesh Chand

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

8 Responses to Back2Basics: The Story of Trait – Part 2

  1. Mahesh Chand says:

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

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

  3. Harish Yarlagadda says:

    In the last code snippet, Cat class extends Animal trait. There is no implementation of walk function. Will this code compile. Shouldn’t Cat class extend AnimalClass?

    • Mahesh Chand says:

      It will compile. Implementation of walk has been moved to Animal$class.class file. And if you see the bytecode of Cat, You can notice line number 6, invokestatic call to walk method of Animal$class.

      • Harish Yarlagadda says:

        Can you try copying the Scala code from last snippet and compiling?

      • Mahesh Chand says:

        Got it, What you were trying to say. Last code snippet i was trying to say what happens behind the scenes. Compiler creates abstract class itself. It has been used to demonstrate only what is happening under the hood.

  4. Pingback: Back2Basics: The Story of Trait – Part 3 | 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