Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection with Scala

I was searching a way of doing dependency injection in Scala kind of like Spring or Unity in C# and I found nothing really interesting.

  • MacWire: I don't understand the benefit as we have to give the class in wire[CASS]. So what's the point if you give the implementation when you call wire? I can do new CASS it will be the same.
  • Cake pattern with self type: Seems to not answer what I'm searching for.

So I decided to make my implementation and ask you what do you think because it's surprising me that nothing like this has been done before. Maybe my implementation have lot's of issues in real life also.

So here is an example:

trait Messenger {
  def send
}

class SkypeMessenger extends Messenger {
  def send = println("Skype")
}

class ViberMessenger extends Messenger {
  def send = println("Viber")
}

I want here to inject everywhere in my app the implementation configured in only one place:

object App {
  val messenger = Inject[Messenger]

  def main(args: Array[String]) {
    messenger.send
  }
}

Note the Inject[Messenger] that I define like below with the config I want (prod or dev):

object Inject extends Injector with DevConfig

trait ProdConfig {
  this: Injector =>
  register[Messager](new SkypeMessager)
  register[Messager](new ViberMessager, "viber")
}

trait DevConfig {
  this: Injector =>
  register[Messager](new ViberMessager)
  register[Messager](new ViberMessager, "viber")
}

And finally here is the Injector which contains all methods apply and register:

class Injector {
  var map = Map[String, Any]()

  def apply[T: ClassTag] =
    map(classTag[T].toString).asInstanceOf[T]

  def apply[T: ClassTag](id: String) =
    map(classTag[T].toString + id).asInstanceOf[T]

  def register[T: ClassTag](instance: T, id: String = "") = {
    map += (classTag[T].toString + id -> instance)
    instance
  }
}

To summaries:

  • I have a class Injector which is a Map between interfaces/traits (eventually also an id) and an instance of the implementation.
  • We define a trait for each config (dev, prod...) which contains the registers. It also have a self reference to Injector.
  • And we create an instance of the Injector with the Config we want
  • The usage is to call the apply method giving the Interface type (eventually also an id) and it will return the implementation's instance.

What do you think?

like image 379
Joan Avatar asked Feb 25 '26 02:02

Joan


1 Answers

You code looks a lot like dependency injection in Lift web framework. You can consult Lift source code to see how it's implemented or just use the framework. You don't have to run a Lift app to use its libraries. Here is a small intro doc. Basically you should be looking at this code in Lift:

package net.liftweb.http

/**
 * A base trait for a Factory.  A Factory is both an Injector and
 * a collection of FactorMaker instances.  The FactoryMaker instances auto-register
 * with the Injector.  This provides both concrete Maker/Vender functionality as
 * well as Injector functionality.
 */
trait Factory extends SimpleInjector

You can also check this related question: Scala - write unit tests for objects/singletons that extends a trait/class with DB connection where I show how Lift injector is used.

like image 55
yǝsʞǝla Avatar answered Feb 26 '26 16:02

yǝsʞǝla