October 21, 2009 — Mario Gleichmann

As a kid, i loved to play with Lego bricks, especially to build freaky spacecrafts.

At that time it was easy to let my phantasy go (where noone has gone before) and build completely new models simply by composing some standard bricks. Those bricks weren’t too specialized, meaning that there weren’t too many constraints on how to combine them. On the other side you always had to compose a new spacecraft from the very ground up as there weren’t some more higher organized units like engines or control cabins.

Nowadays, you’ll find such units. There are engines, control cabins or a whole commando bridge, Wings, Field Generators and so on – a whole set of higher organized units whithin a single domain. On the other side, you can’t combine every unit with an arbitrary other unit within that domain since there are some ‘constraints’ that will prohibit some unsound combinations.

Now you may ask how that cute childhood story relates to Scala?

You may have seen already some similarities to the field of software development where you also want to compose some higher organized building blocks within a certain domain, enforcing that they are only combined in a proper way. It turns out, that Scala’s concept of traits provide some mechanisms of ‘mixin’ them together while enforcing the compliance of some constraints. This may sound too abstract at that point, but hold on – we’ll build some spacecrafts in the above mentioned way and things will get clearer.

Look, it’s a spacecraft

Let’s start with a hull for our spacecraft. To keep things simple and to focus on the core idea of constrained

composition, the spacecraft’s hull will only provide one abstract method engange to start the craft:

abstract class Spacecraft{ def engage }

As you can see, method engage and therefore the whole class is abstract, so you can’t instantiate a pure hull

of a spacecaft. So whenever we want to build a full fledged craft, we may have to ‘add’ (or mix in) a component

that knows how to engage that craft.

Captains place

Typically, a spacecraft possess a kind of ‘control center’ which is normally well suited for initiating the

start of a craft, hence should provide an implementation for method engage. There may be different kinds of

control centers that could be used for building your own, customized spacecraft – e.g. a whole commando bridge for

those big deep space crafts or a small control cabin for those little crafts mainly maneuvering near the orbit.

trait CommandoBridge{ def engage { for( _ <- 1 to 3 ){ speedUp } } def speedUp }

Now we see what it means to engage (a Spacecraft) if composing a commando Bridge to the hull. We simply speed up that craft 3 times.

But hold on – although we know what it means to engage that craft, speeding up that craft is not in the responsibility of the commando bridge, since speedUp is left abstract (speeding down is omitted since it follows the same mechanism – you get the idea).

Re-calibrating all Dilithium crystals

So the spacecraft seems to be incomplete without a unit to speed it up – let’s call such a unit ‘engine’. Again, there may be different kinds of engines we could select from to assemble our craft.

Let’s say there is a Pulse-Engine that directly supports the command of speeding up:

trait PulseEngine{ val maxPulse: Int var currentPulse = 0; def speedUp { if( currentPulse < maxPulse ) currentPulse += 1 } }

As you can see, a PulseEngine is able to speed up until a maximum pulse rate. In order to ‘produce’ different pulse engines (supporting different maximum pulse rates for different types of crafts), the field is again left abstract.

Now we could create our first spacecraft, using a commando bridge and a pulse engine (let’s say that’s all you need for building a full fledged spacecraft).

class StarCruiser extends Spacecraft with CommandoBridge with PulseEngine{ val maxPulse = 200 }

As you can see, we’ve created a new (Sub-)Type of a spacecraft and mixed in both Traits, obtaining a commando bridge (that knows how to engage the whole craft) and an engine (that knows how to get the craft into speed when engaging the craft).

The only thing left is to define the maximum pulse rate our StarCruiser is able to achieve.

Wiring

In the above case, all units fitted together smoothly. For example, a pulse engine provided exactly the ‘interface’ (speedUp) that was needed by a commando bridge, so you could compose both without additional work. Let’s take a look at another control center, that we could apply to our craft, that may offer an incompatible ‘interface’ :

trait ControlCabin{ def engage = increaseSpeed def increaseSpeed }

This time we need to do some additional wiring, if we want to compose a new type of craft using a control cabin and a pulse engine, since both units don’t fit together directly (the dependency needed by ControlCabin (increaseSpeed) isn’t directly fulfilled by PulseEngine)

class Shuttle extends Spacecraft with ControlCabin with PulseEngine{ val maxPulse = 10 def increaseSpeed = speedUp }

As you can see, we have to wire together the control cabin with the pulse engine in order to let them cooperate.

In the same way, we could think of another kind of engine which offers a completely different ‘interface’:

trait WarpEngine extends Engine{ val maxWarp: Int var currentWarp = 0; def toWarp( x: Int ) { if( x < maxWarp ) currentWarp = x } }

Again, we need to wire together the concrete control center with the WarpEngine, depending on their incompatible ‘interfaces’.

Let’s compose a craft, using a commando bridge and a warp engine.

Firstly, we are forced to define a maximum warp level, since it’s an abstract field of WarpEngine. Secondly we have to wire together the commando bridge with the warp engine, that is to ‘route’ the commando bridge’s method speedUp to the warp engines ‘interface’ toWarp with an appropriate implementation:

class Explorer extends Spacecraft with CommandoBridge with WarpEngine{ val maxWarp = 10 def speedUp = toWarp( currentWarp + 1 ) }

Alternatively, we could also use a simple control cabin for another type of spacecraft. Again we have to link the contol cabins commands (increaseSpeed) to the warp engines ‘interface’:

object Defiant extends Spacecraft with ControlCabin with WarpEngine{ val maxWarp = 20 // claimed by WarpEngine def increaseSpeed = toWarp( 10 ) // claimed by ControlCabin }

Restricted Access

Until now, we only applied a control center or engines to spacecrafts. But nothing would restrict us to use those units in other domains so far. Say we want to build a certain airplane and apply a warp engine.

class Jet extends Airplane with WarpEngine{ val maxWarp = 5 }

It’s propably not the best idea to equip a Jet with a warp engine, since this seems to be a bit oversized for an airplane. We need a way to restrict the usage of warp engines – they should be only applied to spacecrafts. Fortunately we can express this kind of constraint, using Scala’s self type annotation. Included within a trait, it’s like saying ‘this trait is only allowed to be mixed into a type of x‘ (in our case ‘Spacecraft‘):

trait WarpEngine extends Engine{ this: Spacecraft => ... }

As you can see, we used the WarpEngines self type to restrict its appliance only to spacecrafts. In all other cases, Scala’s compiler will complain about an unsound mixin.

What makes a spacecraft a spacecaft ?

With selftypes, we now have an instrument to restrict the usage of a trait to be mixed in only to a certain Type.

On the other side, we aren’t forced to use a control center or an engine at all if creating a new spacecraft, since we could provide an implementation of the spacecrafts abstract methods directly within a subtype. That may be fine in some cases, but what if we want to state that a spacecraft has to be composed of at least a certain type of control center and a certain type of engine? Again, we can use the service of the self type annotation, this time applied to our abstract class spacecraft, stating that a spacecraft should at least be compound of a control center and an engine:

abstract class Spacecraft{ this: ControlCenter with Engine => ... }

The only thing left is to provide an appropriate type ControlCenter resp. Engine and the correct classification of those concrete units (e.g. ‘CommandoBridge is a ControlCenter‘)

trait ControlCenter trait CommandoBridge extends ControlCenter{ ... } trait ControlCabin extends ControlCenter{ ... } trait Engine trait PulseEngine extends Engine{ ... } trait WarpEngine extends Engine{ ... }

Summary

Abstract methods and self type annotations are two powerful tools which help to guide or constrain the composition of traits.

You may use abstract methods and abstract fields to enforce a kind of ‘wiring’ between multiple units or at least to force the definition of some concrete information.

You may use a self type annotation to restrict the appliance of a trait, so that it can only be mixed in to a certain type (or subtypes). On the other side, you’re able to enforce that a certain trait (or subtype) have to be mixed in to a certain type, again by using a self type annotation.

In all cases, the ‘composer’ of those units will be guided by the compiler – you can’t forget to give a definition for an abstract method or arrange an unsound composition, since all those ‘constraints’ are based on Scala’s statically typed Type system.