Scala in practice: Traits as Mixins – Motivation

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.

About these ads
Posted in Scala. 9 Comments »

9 Responses to “Scala in practice: Traits as Mixins – Motivation”

  1. Scala in practice: Traits as Mixins – Motivation « brain driven … - 2Dinternational Says:

    [...] Gleichmann. Some voices say that Scala’s type system is rich but complex. Excerpt from:  Scala in practice: Traits as Mixins – Motivation « brain driven … :are-part, but-required, but-their, posted, Success, traits, trouble-listening, [...]

  2. GoogleGuy Says:

    Glad I came back to this site some new very interesting items which I wanted to know more about. Great work on your site.

  3. Sakuraba Says:

    Thank you for this article. I didnt understand traits and was somewhat afraid of them, but they actually are very simple!

  4. Rogério Says:

    Interesting language feature. I wonder if something similar can be implemented in Java…
    For example:

    @Singer @Flyer
    class Bird {} // Bird's classfile is transformed at runtime
    

    and

    Person p = new Person();
    Singer s = mixin(p, Singer.class); // class Person is redefined or retransformed
    s.sing(); // calls "sing" method for the "p" instance only
    

    The terms “transformation” and “redefinition” above refer to

    java.lang.instrument

    .

    • Mario Gleichmann Says:

      Rogerio,

      the only thing that comes to my mind and may be close to the idea of composing multiple ‘features’ (without compromising type safety) is to use a dynamic proxy.
      But dynamic proxies put some constraints on their usage (there have to be an interface for every ‘component’ / no mixing of partially abstract classes / casting to the different ‘facets’ should the proxy reflect multiple interfaces), that you won’t face using traits.

      Greetings

      Mario

  5. iirekm Says:

    Something like this is already in Java, (but it’s immature):

    http://www.qi4j.org/

    http://cglib.sourceforge.net/apidocs/net/sf/cglib/class-use/Mixin.html

  6. mcluvin Says:

    Um… Not to be pedantic, but the point of mixins is WAY more limited in scope to what you’re doing here. The problem, as I see it, is that the Radio, Bird, Cicada, and Person all are likely to have different mechanisms for singing.

    I.e. Different implementations to produce the similar output. Using an Interface just says that it needs to be capable of singing, but doesn’t assume it knows how the thing sings.

    Honestly if they really function that much alike in how they sing, you can probably add a “Singer” class and just use composition (interface Singable {Singer getSinger();}. Then implement the “default” singer and extend it as needed. So you’re really only saving the difference in keystrokes between “with MixinName” and “return this.singer;”

    The only real utility of mixins that i’ve seen is meta computing. Things like equality checking, comparison, reflective data conversion (object to json/xml) etc. Where the “type” you’d pass to the mixin function would be Object and comparing any object to any other. Like if something should be sorted by it’s numeric field, numeric sorting always works the same way so the method you’d write implementing the “comparable” interface would be the same from class to class. The mixin/trait there would save you the time, because the “default” implementation is likely to always be the same, regardless of the class. Exceptions can then be overriden.

    In your example, i can totally see mixing in Singer but then needing to actually override sing() in every class that uses it because if they probably have different internals for HOW they sing.

  7. Kumar Says:

    very brainy articles on Scala … now i can dig into Scala .. i guess … and thank you for all these Scala articles


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 43 other followers

%d bloggers like this: