How to use Groovy Traits

Posted By : Rohan Jain | 18-Nov-2014

In this blog i'll discuss about one of the newer features of groovy, introduced with Groovy 2.3 release.

So What are Traits ?

Traits are reusable components basically set of methods or fields that you can make your class implement.

 

Why you should use them ?

You must have heard of problems of multiple inheritence when working with java and also familiar with the well known situation of what is know as 'Diamond problem'.It says that if you have two classes B and C inherit from A, and class D inherits from both B and C. If there is a method in A that B and/or C has overridden, and D does not override it, then which version of the method does D inherit: that of B, or that of C ??

 

e.g. source (http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem )
Consider a scenerio of where we are developing a gui software and we create a class Button. Now according to appearance it can inherit from Rectangle Class and also inherit from Clickable due to the functionality i.e. handling input clicks. And  the classes Rectangle and Clickable both inherit from the Object class. Now if we create a button object and calls the equals method for it and there is no such method in the Button class and we have an overridden method equals in our Rectangle or Clickable (or both) classes, so how do our button object decide to which method does it calls from its two parent classes (having method of same names)?

 

The situation is like we dont know from which parent class a particular feature is inherited from if more than one parent class implements the feature. 

 

So traits allows the composition of behavior without going into the “diamond inheritance” problem allowing you to decide which behavior prevails upon conflict.

 

At first we'll see,

 

How to use them 

Traits can be seen as interfaces carrying both default implementations and state. 
A trait is defined using the trait keyword

trait HelloWorld {                           
        String helloworld() { "HelloWorld!" }          
}

Then we can use it like a normal interface using the implements keyword 

class A implements HelloWorld {}          
def a = new A()                              
assert a.helloworld() == "HelloWorld!"  

 

How does it solve Multiple inheritance conflicts

trait A {
    String someMethod() { 'Do This' }               
}
trait B {
    String someMethod() { 'Do That' }               
}
class C {}

class C implements A,B {}  

 

Default behaviour

when we call c.someMethod(), he default behavior is that methods from the last declared trait wins. Here, B is declared after A so the method from B will be picked up

assert c.someMethod() == 'Do That'

 

Desired behaviour

In case this behavior is not the one we want, we can explicitly choose which method to call using the Trait.super.foo syntax. In the example above, we can force to choose the method from trait A, by using this:

class C implements A,B {
    String someMethod() { A.super.someMethod() }    
}

def c = new C()
assert c.someMethod() == 'Do This'

 

You can also implement a Trait at Runtime as

trait Runtime {
    String runTimeMethod() { "I'm a run time method" }            
}
class A {                                       
    String someMethod() { 'Do This' }                
}
def s = new A() as Runtime
s.runTimeMethod()
s.someMethod()

Implementing multiple traits at once

trait A { void methodFromA() {} }
trait B { void methodFromB() {} }
class C {}
def c = new C()
def d = c.withTraits A, B           
d.methodFromA()                     
d.methodFromB()

Since Java 8 introduces default methods on interfaces Prior to Java 8, Java was not subject to the Diamond problem risk, as Java does not support multiple inheritance. The default interface method capability added with Java 8 introduced a type of multiple inheritance since classes can implement more than one interface, which can contain default methods that have the same name.

So how traits are differnet from Java 8 default methods

Traits behave the same but with a major difference: the implementation from the trait is always used if the class declares the trait in its interface list and that it doesn’t provide an implementation. Consider we have a class and a trait

Class A {
  void someMethod()	{ // Some implementation in super class for this method
   }
}

trait T {
   void someMethod() { // some different implementation in trait for the same method
    }
}

Consider two classes that extends class A and implements trait T

class B extends A implements T {}
class C extends A implements T {}

 

 

So even if we have someMethod() already implemented in the super class, but the classes B and C declares the trait in its interface list, the behavior will be borrowed from the trait implementation!

About Author

Author Image
Rohan Jain

Rohan is a bright and experienced web app developer with expertise in Groovy and Grails development.

Request for Proposal

Name is required

Comment is required

Sending message..