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:
Reblogged this on Agile Development and commented:
Back2Basics: The Story of Trait – Part 2
Pingback: Back2Basics: The Story of Trait – Part 1 | Knoldus
Reblogged this on Harmeet Singh(Taara).
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?
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.
Can you try copying the Scala code from last snippet and compiling?
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.
Pingback: Back2Basics: The Story of Trait – Part 3 | Knoldus