July 19, 2009 — Mario Gleichmann

Some voices say that Scala’s type system is rich but complex.

Traits are part of Scala’s type system, but their application isn’t that mysterious nor is it incomprehensible.

This post will give some introduction to one of their main operational areas – Traits used as Mixins, a well known concept which is already provided by some dynamic languages like Ruby.

Mixins

As their name reveals, Traits are usually used to represent a distinct feature or aspect that is normally orthogonal to the responsibility of a concrete type or at least of a certain instance. Therefore, the functionality of a Trait may be required by completely different types that have nothing in common or aren’t even members of the same type hierarchy.

Let’s say you want to model the ability to sing as such an orthogonal feature: it could be applied to Birds, Persons (well, not all) or even to Radios (c’mon, with just a little bit of imagination).

In Java, you could come up with an Interface in order to express this ‘trait’:

public interface Singer{ public void sing(); }

Now every type which is also a singer may implement this interface and give an appropriate implementation:

public class Bird implements Singer{ ... public void sing(){ ... } } ... public class Cicada extends Singer{ ... public void sing(){...} }

Now all of them (and their subclasses) can be treated as Singers even – as said – a Cicada is not a Bird nor a Radio.

If some of them (or all) should sing the same way, you could use ‘copy n paste’ or place a default implementation and use composition. But nevertheless, you have to provide a definition of sing() in every of that classes – if only because to delegate to that implementation.

No matter which option you choose, the proportion of boilerplate code isn’t just small (Inheritance may be no option at all, because there may be no common parent class. Particularly, placing sing() into a too general supertype would mean that ALL subtypes would be singers).

Mixin’ traits ‘statically’

Scala provides an elegant way to define what it means to sing (at least a default implementation) and reuse it quite idependently by separating that feature as a trait and using that trait as a mixin.

That said, you can (but don’t have to) provide a definition for some or all methods of that trait and mix that trait into every type you want to:

trait Singer{ def sing { println( "singing ..." ) } } ... class Bird extends Singer

As you can see, the class definition of class Bird has mixed trait Singer into it’s own definition using keyword ‘extends‘.

Now Bird has mixed in all methods (and all other members of the trait) into its own definition as if class Bird would have defined method sing() on its own – no boilerplate delegation code necessary.

Of course you now can ask every instance of a Bird to sing.

A last word on keyword ‘extends‘: you also (or normally) use it to let a class inherit from a superclass. In case of a trait you only use it if you don’t inherit from a superclass and then only for mixin in the first trait. All following traits (should you want to mix in more than one trait) are mixed in using keyword ‘with‘:

class Insect class Cicada extends Insect with Singer class Bird extends Singer with Flyer // given Flyer as another trait

Mixin’ traits ‘dynamically’

In case of class Person, we face another special problem: We only want some instances of Person to be singers. We can’t implement interface Singer on class Person since this would turn every instance of Person into a singer.

Fortunately, Scala allows to mix in a trait ‘dynamically’ when creating a new instance of a class. In that case, only that special instance will be a singer and provide the methods of that trait:

class Person{ def tell { println( "here's a little story ..." ) } } val singingPerson = new Person with Singer person.sing

As you can see, we’ve created a new instance of type Person, saying that this instance is also a Singer by using keyword ‘with‘.

Actually, we’ll receive an instance of a new anonymous class that is a Person as well as a Singer.

println( "class of singing person: " + singingPerson.getClass ) // -> com.mgi.traits.TraitsAsMixins$$anon$2 println( "class of singing person is a Person? " + singingPerson.isInstanceOf[Person] ) // -> true println( "class of singing person is a Singer? " + singingPerson.isInstanceOf[Singer] ) // -> true

Unlike in Java you could call any method on that instance without any typecast (at least within the scope where you’ve created that singing Person), no matter if the method was originally defined within Person or Singer.

Of course you may encounter some problems when sending that ‘special’ singing instance to a method that expects a parameter of type Person. Within that methods scope, a Person (in general) isn’t a singer, therefore calling sing() would cause an error since method sing() is no regular member of class Person.

Is it a Bird? Is it a Singer ? …

In that case, Pattern Matching may come to the rescue. Since you could also try to match against an arbitrary type, we could also try to match a Person against trait Singer. Let’s say we want to cast some Persons for a Show. If that Person is a singer, she should sing, otherwise tell a story …

def cast( p: Person ) { p match { case s: Singer => s.sing case _ => p.tell } }

Conclusion

Scala’s traits are an elegant way to separate concerns. Every feature may be separated within an own trait and can than be mixed into every type or instance that should posses that trait. This first introduction only gave some superficial examples, motivating why and how to use traits as Mixins.

The next ones will deal with some more interesting questions like how to claim that a trait may only be mixed into types (or in conjunction with some other traits) that offer some needed characteristics or how to leverage Mixins in order to inject some Dependencies into the class the trait is gonna be mixed in.