-
Dependency Injection in Scala: Extending the Cake Pattern
Posted on December 14th, 2010 20 commentsContinuing the mini-series on Dependency Injection (see my previous blogs: problems with DI, assisted inject for CDI and improving assisted inject), I took a look at how DI is handled in Scala.
There are several approaches, one of the most interesting being the Cake Pattern. It is a DI solution that uses only native language features, without any framework support. For a good introduction see either Jonas Boner’s blog (on which this post is largerly based) or Martin Odersky’s paper Scalable Component Abstractions.
I would like to extend the Cake Pattern to allow defining dependencies which need some user-provided data to be constructed (like in autofactories/assisted inject).
The Cake Pattern: interfaces
But let’s start with an example of the base pattern. Let’s say that we have a
Userclass,sealed case class User(username: String)
and that we want to create a
UserRepositoryservice. Using the Cake Pattern, first we create the “interface”:trait UserRepositoryComponent { // For expressing dependencies def userRepository: UserRepository // Way to obtain the dependency trait UserRepository { // Interface exposed to the user def find(username: String): User } }We have three important things here:
- the
UserRepositoryComponenttrait will be used to express dependencies. It contains the component definition, consiting of: - a way to obtain the dependency: the
def userRepositorymethod (could also be aval, but why adefis better I’ll explain later) - the interface itself, here a
UserRepositorytrait, which gives the functionality of locating users by username
The Cake Pattern: implementations
An implementation of a component looks pretty similar:
trait UserRepositoryComponentHibernateImpl extends UserRepositoryComponent { def userRepository = new UserRepositoryImpl class UserRepositoryImpl extends UserRepository { def find(username: String): User = { println("Find with Hibernate: " + username) new User(username) } } }Nothing special here. The component implementation extends the “interface” component trait. This brings into scope the
UserRepositorytrait, which can be implemented.Using dependencies
How can one component/service say that it depends on another? Scala’s self-type annotations are of much use here. For example, if a
UserAuthorizationcomponent requires theUserRepository, we can write this as follows:// Component definition, as before trait UserAuthorizationComponent { def userAuthorization: UserAuthorization trait UserAuthorization { def authorize(user: User) } } // Component implementation trait UserAuthorizationComponentImpl extends UserAuthorizationComponent { // Dependencies this: UserRepositoryComponent => def userAuthorization = new UserAuthorizationImpl class UserAuthorizationImpl extends UserAuthorization { def authorize(user: User) { println("Authorizing " + user.username) // Obtaining the dependency and calling a method on it userRepository.find(user.username) } } }The important part here is
this: UserRepositoryComponent =>. By this code fragment we specify that theUserAuthorizationComponentImplrequires some implementation of theUserRepositoryComponent. This also brings the content of theUserRepositoryComponentinto scope, so both the method to obtain the user repository and theUserRepositorytrait itself are visible.Wiring
How do we wire different components together? Again quite easily. For example:
val env = new UserAuthorizationComponentImpl with UserRepositoryComponentHibernateImpl env.userAuthorization.authorize(User("1"))First we need to construct the environment, by combining all of the components implementations that we want to use into a single object. Next, we can call methods on the environment to obtain services.
What about testing? Also easy:
val envTesting = new UserAuthorizationComponentImpl with UserRepositoryComponent { def userRepository = mock(classOf[UserRepository]) } envTesting.userAuthorization.authorize(User("3"))Here we have mocked the user repository, so we can test the
UserAuthorizationComponentImplin isolation.defs overvalsWhy are
defs in the component definition better as the way to obtain the dependency? Because if you use aval, all implementations are locked and have to provide a single dependency instance (a constant). With a method, you can return different values on each invocation. For example, in a web environment, this is a great way to implement scoping! The method can read from the request or session state. Of course, it is still possible to provide a singleton. Or a new instance of the dependency on each invocation.Dependencies that need user data
Finally, we arrive to the main point. What if our dependencies need some data at runtime? For example, if we wanted to create a
UserInformationservice, which wraps aUserinstance?Well, who said the the methods by which we obtain the dependencies need to be parameterless?
// Interface trait UserInformationComponent { // What is needed to create the component def userInformation(user: User) trait UserInformation { def userCountry: Country } } // Implementation trait UserInformationComponentImpl extends UserInformationComponent { // Dependencies this: CountryRepositoryComponent => def userInformation(user: User) = new UserInformationImpl(user) class UserInformationImpl(val user: User) extends UserInformation { def userCountry: Country { // Using the dependency countryRepository.findByEmail(user.email) } } } // Usage val env = new UserInformationComponentImpl with CountryRepositoryComponentImpl env.userInformation(User("someuser@domain.pl")).userCountryIsn’t this better than passing the
Userinstance as a method parameter?Using the Cake Pattern, creating stateful dependencies, which can be created at run-time with user-provided data, and still depend on other components is a breeze. This is similar to a factory method, however with much less noise.
The good and the bad
The good:
- no framework required, using only language features
- type safe – a missing dependency is found at compile-time
- powerful – “assisted inject”, scoping possible by implementing the dependency-providing method appropriately
The bad:
- quite a lot of boilerplate code: each component has a component interface, implementation, service interface and service implementation
However, I don’t think defining all four parts is always necessary. If there’s only one implementation of a component, you can combine the component interface and implementation into one, and if there’s a need, refactor later.
Adam
15 responses to “Dependency Injection in Scala: Extending the Cake Pattern”

-
You missed a big point, that we use extensively–by using def’s in place of val’s, it is possible to extend a component. An the overriding access method can also reflect the extending component.
So you can have a base component which is widely known and a subcomponent known by a few other components. And those few components which are aware of the subcomponent can use its additional methods because the dependency (this: X =>) identifies the subcomponent.
In AgileWiki we use the cake pattern both for the major components of the system and for the elements of our DOM.
–b
-
Stephen December 16th, 2010 at 22:14
If you’re doing a DI mini-series, you might also take a look at:
http://sonymathew.blogspot.com/2009/11/context-ioc-revisited-i-wrote-about.html
It is the same sort of “framework-less DI” approach of Cake, but just inner-interfaces instead of container-traits/self-types. Which to me makes it simpler to understand.
Personally, I don’t have a lot of outside-my-app code reuse, so have gotten by nicely with a single ApplicationContext interface, which is like the union of each service’s inner-interface in Context IoC merged into one.
-
When building a program of singleton components, initialization order gets critical. The obvious answer is to make the factory methods lazy. I.E. Create the nested object on request, and only if not already created.
This makes it possible to start building a library of components that you can use in composing new programs.
-
Tymur Porkuian December 26th, 2010 at 01:14
If we have two components like these:
1) new UserAuthorizationComponentImpl with UserRepositoryComponentHibernateImpl
2) new UserSomethingElseComponentImpl with UserRepositoryComponentHibernateImpl
Wouldn’t “new UserRepositoryImpl” be called twice?
-
Vladimir January 3rd, 2011 at 03:38
At first, I want to thank you for the most actual and simple description of this pattern.
I think that the previous commentor meant the other thing, look, when you’re using one component in two different components, two instances of the component used will be created.
For instance, I have DatabaseComponent and two components using it UsersComponent and SalesComponent. I have Database object within DatabaseComponent created twice despite of “val database = new H2()” declaration.
The simple solution I am maintaining now is to hold static collection (object) of already created instances and take database instances from there at “def database”. It is not going to be a good solution. It would be great if you could suggest something better.
Thank you.
Vladimir. -
Vladimir January 3rd, 2011 at 17:24
Yes, almost exactly.
My UI is the Circumflex RequestRouter and it is the environment itself:
class RequestProcessor extends RequestRouter
with H2Component // implementation of the DatabaseComponent
with DatabaseSalesComponent
with DatabaseUsersComponent {
…
}trait DatabaseSalesComponent extends SalesComponent {
this: DatabaseComponent =>
…
}trait DatabaseUsersComponent extends UsersComponent {
this: DatabaseComponent =>
…
}trait H2Component extends DatabaseComponent {
def database: Database = {
// XXX:
H2Databases.synchronized {
H2Databases.get match {
case Some(database) => database.asInstanceOf[Database]
case None => {
H2Databases.set(new H2()).asInstanceOf[Database]
}
}
}
}
}Doing this I have H2Component.database called a few times almost simultaneously. It reminds me the http://en.wikipedia.org/wiki/Diamond_problem.
-
Vladimir January 3rd, 2011 at 23:19
RequestRouter is like a Servlet (hence it is created just once).
I have multiple Database instances created after one “Servlet” creation. -
Hi Adam. You’ve become a victim of a popular misconception about the Cake Pattern, because DI is actually a small part of this rather complex pattern – I’ve blogged about that in more details here:
http://biased-and-fair-software-development.blogspot.com/2011/01/slicing-cake.html
Your post may suggest, that using Scala to do DI requires a lot of boilerplate, however this is false, because you shouldn’t use the full Cake, when all you need is DI. Self-types will do and they are a lot simpler than the full pattern.
5 Trackbacks / Pingbacks
-
[...] Dependency Injection in Scala: Extending the Cake Pattern @ Blog of Adam Warski (tags: scala dependencyinjection di cake-pattern patterns) [...]
-
[...] DI and DI containers which would use pure Scala; a promising candidate is the Cake Pattern (see my earlier blog post for information on how the Cake Pattern works). FP enthusiast also claim that they don’t need [...]
-
[...] possibility of scoping your code is using nested classes, or even to go further and use the Cake pattern in Scala. Apart from the old problems: what package to use and how to name the module class, we’ve got [...]
-
[...] As a side note, this is a good example where Cake Pattern performs better since it allows to use def in very natural [...]
-
[...] in Scala, but there is also a method which relies on native library features, the Cake Pattern. Adam Warski’s post from 2010 is a good summary of the idea, with code [...]
Leave a reply
- the











Twitter
Bill La Forge December 16th, 2010 at 15:23