Traits As Stackable Modifications
Traits are similar to Java’s interfaces. Classes and objects can extend traits, but traits cannot be instantiated and hence have no parameters. It also supports multiple inheritance. Traits are created using trait keyword.
Syntax:
trait Trait_Name { // Fields.. // Methods.. }
super keyword: It is used whenever a base and subclass have same-named methods so in order to resolve ambiguity we use the super keyword to call base class method.
Stackable Modification with Traits
Before, moving further first we should understand what is a Stackable Modification with the help of an example. Consider a customer who pays to Recharge his mobile phone to use mobile services such as voice calling, internet, etc. These services can be divided into different packages as per a particular user’s usage. If we want to implement this service we would be required to have the name of the package for which the customer has paid for a particular package, let’s say DataPack. So we can say the following.
new Recharge with DataPack
Assuming that we have particular value in our Recharge class that has the list of services listed in a certain pack. What if the consumer wants to Recharge to one more pack, and we don’t want to have a mechanism that will explicitly modify the list of the services for us, but it should happen by default. This is like a behavior that is getting modified as we keep adding different packs. This kind of situation gets us know to the concept of stackable modifications. With the customer adds a new pack the list will keep on updating.
new Recharge with DataPack with FullTalkTime
Scala supports stackable modifications to any methods using classes or traits that means you can select a very specific behavior by stacking classes and traits by mixing them together. When you stack a new trait by overriding the same method over and over, then you will get a different or add-on behavior to your method.
The following example illustrates how traits can be stacked.
Example 1:
In this example, we used traits to modify methods of a class by using traits in stackable fashion. Here, we use the super keyword to invoke dot() method in both the traits. In this way, we achieved stackable modification. In cases of stackable modification, the method invocation order is determined by linearization rule.
Scala
// Scala program to illustrate traits // in stackable fashion // Defining class shape class Shape { def dot(shape : String) = println( "Dotted : " + shape) } // Using trait keyword // Using super keyword trait Square extends Shape { override def dot(shape : String) = super .dot( "Square-" + shape) } // Using trait keyword // Using super keyword trait Circle extends Shape { override def dot(shape : String) = super .dot( "Circle-" + shape) } // Using trait keyword // Using super keyword trait Sharp extends Shape { override def dot(shape : String) = super .dot( "Sharp-" + shape) } // Defining main object Shapes { def main(args : Array[String]) { val shape 1 = new Shape with Sharp with Square shape 1 .dot( "Shape-1" ) val shape 2 = new Shape with Circle with Sharp shape 2 .dot( "Shape-2" ) } } |
Output:
Dotted : Sharp-Square-Shape-1 Dotted : Circle-Sharp-Shape-2
Example 2:
Scala
// Scala program to illustrate traits // in stackable fashion // Defining class Ball class Ball { def spin(ball : String) = println( "Spinning : " + ball) } // Using trait keyword // Using super keyword trait Yellow extends Ball { override def spin(ball : String) = super .spin( "Yellow-" + ball) } // Using trait keyword // Using super keyword trait Blue extends Ball { override def spin(ball : String) = super .spin( "Blue-" + ball) } // Using trait keyword // Using super keyword trait Shiny extends Ball { override def spin(ball : String) = super .spin( "Shiny-" + ball) } // Defining main object Balls { def main(args : Array[String]) { val ball 1 = new Ball with Shiny with Yellow ball 1 .spin( "Ball-1" ) val ball 2 = new Ball with Blue with Shiny ball 2 .spin( "Ball-2" ) } } |
Output:
Spinning : Shiny-Yellow-Ball-1 Spinning: Blue-Shiny-Ball-2