Sunday 13 November 2011

Scala traits

If you are a Java programmer (like me) then you might have used interface. In Java we define an abstract type by using interface. Interface outlines the contract by just having method signature. It does not have any implementation. Traits are similar to interface but it may contain partial implementation.

So what is a trait?

A trait encapsulates the fields and method definitions. It can be mixed into other classes to add new feature or to modify its existing behavior.

Let me give you a simple example how it can be done:

trait DiscountPerson {
 
     def isDiscountApplied() : Boolean
 
     def discountAmount() : Double = 10.5
 
   }

   class Person(age: Int) extends DiscountPerson {
     
      var myAge: Int = age
  
      def isDiscountApplied() = myAge > 60
 
   }

   object DiscountTraitTest extends Application {
  
     val seniorPerson = new Person(65)
  
     if( seniorPerson.isDiscountApplied() ) 
        println(seniorPerson.discountAmount())
   }

If you see carefully you will find that out of two methods in DiscountPerson trait discountAmount method has the implementation and isDiscountApplied method does not have any implementation.

Any other class can extend the DiscountPerson trait and can have different implementation of isDiscountApplied method to get the same amount of discount. This new class does not need to have discountAmount method again to get the same amount discount. So you can see the benefit of using trait - code reusability.

How does trait work?

By this time you already know how you can write a trait in Scala. A trait definition looks like a class definition except that it uses the keyword trait. In the above example the trait is named DiscountPerson. It does not declare a superclass. It means that it has the default superclass of AnyRef.

Once a trait is defined, it can be "mixed in" to a class using either the extends or with keyword. When we use extends keyword to mix in a trait, we implicitly inherit the trait's superclass. In above example, Person subclasses AnyRef (superclass of DiscountPerson) and mixes in DiscountPerson.

It is also possible to mix a trait into a class that explicitly extends a superclass. In this case, extends can be used to indicate the superclass and with to mix in the trait. For Example:

trait Programmer {
 
     def profile(){
        println("I am programmer.")
     }
 
   }

   class Blogger   

   class John extends Blogger with Programmer {
     
     override def toString = "blogger"  
 
   }

The below example will show you how to mix in multiple traits:

trait Programmer {
 
     def profile(){
        println("I am programmer.")
     }
 
   }

   class Blogger 
   
   trait Photographer 

   class John extends Blogger with Programmer 
                              with Photographer {
     
     override def toString = "blogger"  
 
   }

Few more points to note about trait:

1. I have already mentioned that a trait is similar to an interface but it can have implementation. We can also declare fields in a trait. It means that trait can maintain state. In fact, a trait definition can look exactly like a class definition, with two exceptions:

(a) a trait cannot have any "class" parameters

class Person(age: Int)         // will compile

   trait AnotherPerson(age: Int)  // will not compile

(b) in traits "super" calls are dynamically bound whereas in classes they are statically bound. It means that when we write "super.toString" in a class, we know exactly which method implementation will be invoked. But when we define the trait the method implementation to invoke for the "super" call is undefined. Rather, the implementation to invoke will be determined anew each time the trait is mixed into a concrete class.

2. It is possible to add new feature to a class easily using trait.

3. Trait plays an important role in implementing DCI (Data, Context and Interaction) in Scala easily. More you can read from http://www.artima.com/articles/dci_vision.html

When to use trait?

Rules are simple to find out when to use trait:

(a) You might have noticed I used a term called "code reusability". Remember it. If the behavior might be reused in multiple, unrelated classes then you can make it a trait. Trait has the ability to mixed into different parts of the class hierarchy.
Otherwise make it a concrete class.

(b) Second thing to consider is the efficiency. When efficiency is important, it is better to use a class. Traits get compiled to interfaces. So there is a slight performance overhead. However this point should be considered if there is an evidence that trait in question is creating a performance bottleneck and a class can solve the problem.

(c) If you are not sure then start by making it as a trait. You can change it later on.

Conclusion

In this article I have explained the Scala trait - what it is, how it works, how to use them and benefit of using them. Using trait we are actually creating a unit of code that can be reused through inheritance. If we start any of our Scala project with trait then we are keeping more options open before us. I hope that you have enjoyed reading this article. Any comment is welcome.