How to integrate subcut dependent modules?

684 views Asked by At

Based on available documentation this task seems straightforward, however I've been hitting my head in the wall for a couple of days on this and still can't make it work for a simple inter-module dependency...

Here's a reduced example:

trait Bla {
  def m: String
}

class BlaImpl(implicit val bindingModule: BindingModule) extends Bla with Injectable {
  val s = inject[String]('bla)
  def m = "got " + s
}

object Program extends App with Injectable {
  implicit val bindingModule =
    new NewBindingModule({ implicit module ⇒ module.bind[Bla] toSingle { new BlaImpl } }) ~
      new NewBindingModule(_.bind[String] idBy 'bla toSingle "bla!")
  val bla = inject[Bla]
  assert(bla.m == "got bla!")
}

Running this code fails with the following error, When trying to build the BlaImpl instance:

 org.scala_tools.subcut.inject.BindingException: No binding for key BindingKey(java.lang.String,Some(bla))

Debugging shows that the binding module handed to BlaImpl's constructor doesn't contain the 'bla String in its bindings, and that Program.bindingModule.bindings has all bindings (including the needed String).

I've seen other question similar but it dows refer only to composition but not to dependencies crossing module borders.

What am I doing wrong?

1

There are 1 answers

2
tenshi On BEST ANSWER

Unfortunately it will not work. Even if you merge 2 modules together with subcut, this does not mean that they will see each-others dependencies.

If you want to archive desired results, then you need to pass BindingModule explicitly to the BlaImpl constructor. Something like this:

val anotherModule = new NewBindingModule(_.bind[String] idBy 'bla toSingle "bla!")

implicit val bindingModule =
  new NewBindingModule({ implicit module => module.bind[Bla] toSingle { new BlaImpl()(anotherModule) } })

Module merge will not do the trick in this case. I actually discussed this problem of subcut in this answer. I even created a example code that compares subcut and Scaldi and demonstrates how they both solve this problem (or don't solve it, in case of subcut):

https://gist.github.com/OlegIlyenko/5623423

If I would rewrite your example with Scaldi, then it would be something like this:

import scaldi.{Injector, Injectable, Module, DynamicModule}

trait Bla {
  def m: String
}

class BlaImpl(implicit inj: Injector) extends Bla with Injectable {
  val s = inject[String]('bla)
  def m = "got " + s
}

object Program extends App with Injectable {
  implicit val appModule =
    new Module { bind [Bla] to new BlaImpl } ::
    DynamicModule(_.binding identifiedBy 'bla to "bla!")

  val bla = inject [Bla]
  assert(bla.m == "got bla!")
}

As you can see, in Scaldi modules can see each-others dependencies if they are composed with :: or ++.