Archive for June 28th, 2011

Share on TwitterDigg This

Wow! Part I was good. Had a nice amount of comments, with great suggestions, and of course some complaints (which means I’m in the right direction).

My intention with this series is just to show some of the features of scala, I have no intention to show **all** the features, I lack this capability, for that consider reading Martin Odersky great book (Programming in Scala). But I hope that I pick some of the things that triggered my interest in switching to scala.

So in this post I’ll [try] to explain Traits

Background

Before going into traits, let me add some context here:

First time I’ve heard about Ruby I believe was back in 2006. A friend showed it to me, and as EVERY SINGLE JAVA DEVELOPER OUT THERE, I turned my nose up, and said “This is rubbish, Java is the Alpha and Omega”, man I was more stupid than I am today ;)
But even then, with all my hate against other languages that had features that I was hoping that my loved java language could one day deliver to me. I had to surrender to one feature called Modules and mixins. Man that was nice, I kept dreaming on the possibilities a java developer could achieve with that. 5 years have passed, I still don’t have it on java.
Traits can do that for us, actually it can do more, so if you desire to expand your horizon, have a look on 4 examples on how traits can change your life.


Introduction


Just like java, scala is a single inheritance language. You can only have one parent class. I’ve learned OO by starting with C++, and I still recall Deitel’s book explaining the Diamond problem once you have multiple inheritance on your domain. And I believe that most of us agree on how bad things can turn to be when you have multiple inheritance and don’t know how to use. Remember “guns don’t kill people. People kill people”.

It took me a while to understand the real power of traits. People sometime misunderstand them believing that they are just interface on steroids, but they can be much more. So I’ll try to show 4 nice things I found out that can really help us, and believe me they are helping me.

  1. Traits can have default implementation
  2. Traits support state
  3. Traits are stackable
  4. Traits can be mixed with your code (Best feature ever)


1. Traits can have default implementation



If you are just starting with scala, you can think of traits as something between an abstract class and an interface (I know people are going to kill me in the comments for that). But really, it’s your best bet to try to figure out this feature. So traits behave like interfaces as your class can have more than one. And also as an abstract class as you can have concrete methods on them. That can be really handy. I’ll try to show an example on when.


If you ever had to develop UI code, you will end with hundreds of listeners interfaces. This is good, as you force the behavior to the implementation of the class but also keep it abstract and don’t worry with the implementation at all. But sometimes you just wish you could have the capability of having a default behavior for it.
So imagine this scenario: You have a view class that has to be descendant from AbstractView, you have some listeners you may want to attach, like a DisplayListener. Here’s how your code will end up

public abstract class AbstractView {
	abstract void onload();
}
public interface DisplayListener {
	public void onDisplay();
}
public class MyView extends AbstractView implements DisplayListener{
	@Override
	void onload() {
	}
	@Override
	public void onDisplay() {
		//fire some events here		
	}
}

So every time you wish to have a DisplayListener you will have to implement it’s behavior. That’s acceptable up till you have dozens of classes with the same behavior right? What we usually do with java is change the inheritance of your view class, adding another class on the hierarchy:

public abstract class DisplayView extends AbstractView implements
		DisplayListener {
	@Override
	public void onDisplay() {
		//fire some events here
	}
}
public class MyView extends DisplayView{
	@Override
	void onload() {
	}
 
}

That’s ok, but you kinda messed with your class hierarchy and wouldn’t be nice if you interface could have default behavior? That’s one of the features of Traits:

trait Display {
	def onDisplay() = {
	  //trigger some events here
	}
}
abstract class AbstractView {
	def onLoad()
}
class MyView extends AbstractView with Display {
 
  def onLoad(): Unit = {  }
 
}

See? Using traits you now have the desired behavior and you did not messed with your class hierarchy :) . This first example I must admit is just the least interesting of them all, so please stay with me a little longer and you will enjoy the benefits of traits.

Things to remember:

  1. You use traits by adding with keyword after your class hierarchy. This rule has an exception, if you don’t descend from any super class, than you must extend a trait.
  2. Just like interfaces you can have as many with as you want. Just remember rule #1, if you don’t descend your first trait is added by extends not with


2. Traits support state



By saying this I mean: You can have instance values(variables) inside your trait. I have one example for that, it was the best I could come up with.

I really envy those bloggers that can find great examples for real life. Sometimes, without a context or a user story, it’s hard to show a nice example that makes sense. It’s really the hardest part of writing a blog, trying to figure out an real world example without a context or breaking the NDA of your employer ;)

Well, so here’s my simple example. You are building a multimedia app, and medias are evil things to model. You have images, audio, video, swf files, ppt … the list goes on and on. Some of them share same properties. So modeling this is hard, I’ve been there. Trying to use single inheritance will eventually lead you to some media model that will have more properties than required, just because you decided to took a certain path on your hierarchy.
So, if you use traits, you can mix the properties as you desire. So I apologize for the new “english” words I’ll be using here ok:

class Media(val id:Int) {
 }
trait Viewable extends Media {
	var width:Int = -1;
	var height:Int = -1;
}
trait Listenable extends Media {
	var duration:Int = -1
        var codec:String = "MP3"
}
trait Playable extends Media {
       var frames:Int=-1
}
 
class Image(id:Int) extends Media(id) with Viewable {}
class Audio(id:Int) extends Media(id) with  Listenable {}
class Slide(id:Int) extends Media(id) with Viewable with Listenable {}
class Presentation(id:Int) extends Media(id) with Viewable with Playable{}
class Video(id:Int) extends Media(id) with Viewable with Listenable with Playable {}

As you can see, you can mix and match as many traits as you desire in your model. You don’t compromise your hierarchy, and if you keep your traits to a minimum you can model any type of Media out there.
Things to consider:

  1. If a trait extends a class it means that it can only be applied to that type of class. This is really nice when you start stacking up your traits (next section)
  2. Values (or variables) on traits must have a default value, this may be a turn down, but if you are modeling a domain, you can always call: media.duration = 300 later on
  3. Regarding the previous rule, there’s actually a way of overcoming that, it’s called Initializing abstract vals. Section 20.5 of Programming in Scala, don’t be shy have a look there

This media example is something I had to suffer using Java once in the past. Traits could really helped me out on my modeling there.

3. Traits are stackable



Traits have a nice thing that is the ability to modify a class that they are applied. It works pretty much like overriding on you regular java class. If your class overrides a method of a super class, you can modify it’s behavior. The trick here is that it seems that this is done upside down, your class define a method, you add traits that extend your class, and then on your class you mix the traits and then they modify your method. Tricky to understand? It is, but once you get it new horizon can open before your eyes. I’ll use a slight modified version of Programming in Scala for that.
So you have a list of integers and you want to add operations to it: Doubler -> Doubles each value added to the list, and Adder -> Increments by 1 the value. Here’s the code:

class MyList {
	private val buffer = new ArrayBuffer[Int]
	def put(i:Int) ={
	  buffer += i
	}
}
trait Doubler extends MyList {
   abstract override def put(i:Int) = {
	  super.put(2*i)
	}
}
trait Adder extends MyList {
    abstract override def put(i:Int) = {
	  super.put(i+1)
	}
}

Those are really simple traits, but notice that they override the put method. So let’s imagine you create 4 classes:

class DoublerList extends MyList with Doubler{}
class AdderList extends MyList with Adder{}
class DoubleAdderList extends MyList with Adder with Doubler {}
class AdderDoublerList extends MyList with Doubler with Adder{}

And let’s say you call list.put(2) on each of those, you would get:

DoublerList => 4
AdderList => 3
DoubleAdderList => 5
AdderDoublerList => 6

Scala uses linearization to solve this issue. But to make things simpler, just imagine that when you combine Traits, the super calls are invoked from right to left. So the last trait gets called and if it calls super the trait/class to the left will get called afterwards.

Now this is pretty cool right? Imagine how could you combine traits to achieve different behavior. Just at this example we created 4 classes with 2 traits :) . But the power of traits is yet to be revealed, creating those classes were annoying, there should be a way to avoid that right? And as matter of fact there is. Scala supports the idea of mixins, you can on runtime add traits to your existing classes like this:

val dlist = new MyList with Doubler
val alist = new MyList with Adder
val dalist = new MyList with Adder with Doubler
val adlist = new MyList with Doubler with Adder

Hey you have just created new classes without actually declaring them :P nice huh? So let’s move forward to this topic

4. Traits can be mixed with your code



So traits can be mixed in your code. For a java developer, with it’s short sighted vision, it’s hard to get that. But it’s really a powerful tool. I bet that someone will add comments on how can this be achieved with Proxies or AOP, but again, the whole point here is that scala delivers it as a native part of the language. No need to use boilerplate code. Like patterns.
On the previous section you had a glance on how you could use traits during object initialization to create a complete different behavior for you class. So let me put a good usage of it I found out.
I love Grooyv, and more than Groovy, I love Grails. Whether you like it or not, the ActiveRecord pattern makes things pretty simple. I just love the idea of having my domain class also have the capability of persistence, so it’s not a “fake” object that most domains classes on java projects based on ORM are.
But I’ve tried to use ActiveRecord with Java, and I hated it, because I had to make all my domain classes inherit from a ActiveRecord class that was not supposed to be part of my domain.
Here’s an example on how you can use ActiveRecord with you domain classes intact on Scala:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class User(var name:String, var age:Int) extends Serializable{
 
}
trait ActiveRecord[T] extends Serializable { self =>
 
  def save() : T = {
    //save
    self.asInstanceOf[T]
  }
 
  def update() : T = {
   //update
    self.asInstanceOf[T]
  }
 
  def delete() = {
   //delete from persistence
  }
 
  def load(id:Serializable)= {
    //load from persistence and assign it to self
  }
 
val user = new User("bob",31) with ActiveRecord
user.save

I’m not concerned here on how you will deal with the persistence part. You could use an ORM like Hibernate or a noSQL alternative. The point here is to show how you can add the persistent behavior to your class.

I hope that with this small example you’ll get convinced of the power of traits. As I move on with scala I keep finding usages that are really making my life easier, I hope the same happens to you.
See you on the Part 3
Happy coding!