Christmas Cake pattern

I had a lot of questions yesterday about the use of the cake pattern. (No, we have not invented it; we started Cake Solutions 12 years ago, long before Scala.) Let me explain the differences between the cake pattern, traditional DI and inheritance.

Why Christmas? Well, imagine you’re modelling toy that needs batteries. It does not make sense to have the toy as a subtype of batteries. In code, it would be this horror:

trait Batteries

class AABatteries extends Batteries

// the Toy is actually a pack of AA batteries (!)
class Toy extends AABatteries

val toy = new Toy

Unless your toy is actually a pack of AA batteries, this code does not model reality well.

Turning to traditional DI, that is, dependency injection of instances, you would modify the toy to accept some instance of Batteries; and you would be responsible for creating this Batteries instance.

trait Batteries

class AABatteries extends Batteries

// the Toy needs an instance of Batteries
class Toy(batteries: Batteries)

val batteries = new AABatteries
val toy = new Toy(batteries)

This is better. We correctly separate the Toy and Batteries instances and we clearly say that Toy depends on some externally provided batteries. In this model, though, you might also be able to share the Batteries instance between multiple toys. This may or may not be what you actually want, so think carefully!

If all that you need is the functionality provided by the Batteries and you don’t actually care about the instances, consider using the cake pattern. In the cake pattern, the injection takes the form of when you make an instance of Toy, you must supply the implementation of Batteries. In code, this is simply:

trait Batteries

class AABatteries extends Batteries

// When constructing instance of the toy, supply the batteries
class Toy {
  this: Batteries =>

}

val toy = new (Toy with AABatteries)

So, that’s all the cake pattern does. It expresses type dependencies that must be satisfied when making instances of the dependant types. The compiler checks that you’ve satisfied the dependencies correctly. It is not injection of instances, it is injection of functionality. Let me rephrase that: in the DI of instances, you make an instance of the dependency and then supply the instance when constructing the dependant instance; in the DI of functionality, when you make an instance of the dependant type, you get the compiler to inject the functionality of the dependant type.

This entry was posted in Jan's Blog and tagged , . Bookmark the permalink.

6 Responses to Christmas Cake pattern

  1. Andrea says:

    Unfortunately this means that toy ends up having a type that is both a subtype of Toy and Batteries. Which would mean, toy is both a toy and a pack of batteries… It works, but it meddles thigs quite a bit.

    When it comes to DI in Scala, I think the cleanest way is to use implicits. If the toy needs a pack of batteries, ask for an implicit Batteries in methods that require it. Then, where you need to use it, import the implicit instances you want – typically two different instances, one for the actual application and one for tests. Are there any downsides to this simple solution?

  2. Jan Machacek says:

    I found using implicit instances a bit too murky. It is sometimes difficult to see what value is being used. However, there is some merit in exploring the implicit instances further. To expand on the example I gave, we could have

    class Power {...}
    
    trait PowerSource[A] {
      def getPower: Power
    }
    
    trait Toy {
      def play(power: Power)
    }
    class Hovercraft extends Toy {
      def play(power: Power) = ...
    }
    class Plane extends Toy {
      def play(power: Power) = ...
    }
    
    object Main extends App {
      implicit object HovercraftPowerSource extends PowerSource[Hovercraft] {
        def getPower: Power = // make power for the Hovercraft toy
      }
    
      ...
      
      def play[A <: Toy : PowerSource](t: => Toy) = 
         t.play(implicitly[PowerSource[A]])
    
      play(new Plane)
      play(new Hovercraft)
    }
    

    However, this code (which I hope it is bug-free!) definitely pushes the concept of batteries for toys. But it is powerful, because it completely separates the provision of power and the toys themselves.

  3. Yann says:

    I am quite new to Scala und functional programming.

    I tested dependency injection with the cake pattern and implicits, and I found that the cake pattern needs a lot of traits, and is not so easy to read for me (and probably for other programmers used to imperative style). I found implicits nicer.

    My test code:
    - cake pattern: https://github.com/yanns/play2-scala-DI/tree/master/app/models/cake
    (spec: https://github.com/yanns/play2-scala-DI/blob/master/test/controllers/cake/ApplicationSpec.scala)
    - implicits: https://github.com/yanns/play2-scala-DI/tree/master/app/models/implicitinject (spec: https://github.com/yanns/play2-scala-DI/blob/master/test/controllers/implicitinject/ApplicationSpec.scala)

    Still curious to discover new ways…

  4. Pingback: This week in #Scala (07/12/2012) | Cake Solutions Team Blog

  5. TechNeilogy says:

    I agree that this is an important pattern; I discovered this same pattern earlier this year. I have a Scala inference engine which I run in several flavors: customer mode, rule debug mode, performance test mode, etc., each with different internals and outputs. I started out modeling it using trait inheritance, but then eventually worked my way to trait-based DI as in the “Christmas Cake pattern.” It has really simplified the code and made it easier to add new “flavors” to the engine.

  6. Will Sargent says:

    I found Subcut (https://github.com/dickwall/subcut) to be the cleanest DI solution for Scala — it’s implicits with a composable binding module system.

Leave a Reply