Singletons without Singletons: Scala Type Classes

I was using Guice in a project recently. Objects which did not come out of Guice got their dependencies not injected. So I had a global singleton where objects could get their dependencies. Yeah yeah I know singletons are bad and stuff. It would be nicer to let Guice handle it all, but sometimes this is not possible due to framework restrictions where you have no controll over object creation.

For example one part of the project uses UseCase classes and injects depedencies inside them. I want to use those UseCases with

use(new ActivateEmailAddressUseCase(encrypted))

The definition of the use method is simple and looks like this:

object UseCase {
  def use[R](useCase: {def execute(): R}): R = {
    DomainInjector.injector.injectMembers(useCase)
    useCase.execute()
  }
}

where the global DomainInjector looks like this:

object DomainInjector {
  val injector = Guice.createInjector(new GuiceDomain)
  def injectMembers[I](injectee: I) =  injector.injectMembers(injectee)
}

So far so nice. The problem did arise when I was running only parts of the project against sbt ScalaTest testing. Those parts now were coupled to other parts because of the global singleton and I didn't want to include those other parts as depedencies. Bad. The problem is the GuiceDomain class where dependencies might go to different parts of the application - especially up the hierarchy.

Changing this to an interface implementation

object DomainInjector extends Injector {
  val injector = Guice.createInjector(new GuiceDomain)
  def injectMembers[I](injectee: I) =  injector.injectMembers(injectee)
}

and changing the UseCase class to use an implicit method paramater:

 
object UseCase {
  def use[R](useCase: {def execute(): R})(implicit injector: Injector): R = {
    injector.injectMembers(useCase)
    useCase.execute()
  }
}

Now the tests could include into their scope

object DummyInjector extends Injector {
  def injectMembers[I](injectee: I) = { }
}

instead of the DomainInjector and still work. Excellent, problem solved.

And if you do not know what this has to do with type classes: I do not know either after reflecting about the blog post 5 minutes after publishing. Sorry for that 😉