Programming language: Scala

Cableguy alternatives and similar packages

Based on the "Modularization and Dependency Injection" category

Do you think we are missing an alternative of Cableguy or a related project?

Add another 'Modularization and Dependency Injection' Package



Cableguy is yet another Dependency Injection (DI) library for Scala. It is compile time, macros based and runtime-reflection free.


Build Status codecov.io Gitter

Quick facts

  • It is a compile-time dependency injection implementation (I.e. no runtime-reflection involved)
  • It is implemented with a help of Scala macros
  • It allows you to perform deep Just-In-Time resolution
  • It allows you to explicitly provide your dependencies using providers
  • It allows you to use tagged dependencies
  • It allows you to depend either on a singleton (every time the same instance) or a prototype (every time a new instance)
  • It does not allow you (at least yet) to resolve not concrete types (traits, abstract classes) just-in-time. However you can do it with providers.


This project is published at Maven Central. However, there is no release version yet. To depend on the SNAPSHOT version use the following sbt snippet:

resolvers += Resolver.sonatypeRepo("snapshots")

libraryDependencies ++= Seq(
  "ru.arkoit" %% "cableguy-core" % "0.1.0-SNAPSHOT"

For now this project is compatible only with scala 2.11.*. There is no final decision whether it's worth to support scala 2.10.*.

Just-In-Time resolution

import ru.arkoit.cableguy._

case class A(b: B)
case class B()

val a = Resolver().resolve[A] 
// eq: A(B())

Explicit providers

To declare explicit provider you should extend Provider trait and use method definitions annotated with @provides annotation to provide some service. Then pass all of your providers to the Resolver constructor in a form of Shapeless HList (Do not worry if you do not know what is it, just import shapeless._ and use the following pattern: Resolver(FooProvider :: BarProvider :: HNil)). Obviously, explicit providers have higher priority than Just-In-Time resolution. Provider methods could have dependencies as well

import ru.arkoit.cableguy._
import ru.arkoit.cableguy.annotations._
import shapeless._

case class A(b: B, d: D)
case class B(label: String)
case class C()
case class D(num: Int, c: C)

object SomeProvider extends Provider {
  def provideB = B("Foo")

  def provideD(c: C) = D(10, c)

val a = Resolver(SomeProvider :: HNil).resolve[A]
// eq: A(B("Foo"), D(10, C()))

Tagged dependencies

import ru.arkoit.cableguy._
import ru.arkoit.cableguy.annotations._
import shapeless._

case class A(label: String)

class myTag extends ServiceTag

case class B(@myTag a: A)

object AProvider extends Provider {
  def provideANotTagged = A("not tagged one")

  @provides @myTag
  def provideATagged = A("tagged one")

val result = Resolver(AProvider :: HNil).resolve[B]
// eq: B(A("tagged one"))


Cableguy supports two scopes of dependency resolution: singleton and prototype. If the dependency is annotated with a singletonScope annotation (or is not scope-annotated at all) the same instance of the dependency will be used across all depended services (which depend on the singleton version of this service). If the dependency is annotated with a prototypeScope annotation, new instance of the dependency will be provided to each dependent service. The following example clearly demonstrates this behavior:

val r = scala.util.Random

class B {
  val rn = r.nextInt

class D {
  val rn = r.nextInt

class C(b: B, @prototypeScope d: D)
class A(c: C, b: B, @prototypeScope d: D)

val a = Resolver().resolve[A]

a.b.rn == a.c.b.rn // returns true
a.d.rn == a.c.d.rn // returns false

Other considerations

Probably, the best way to use this library is to resolve single, top-level, "bootstrap" object to build single dependency tree. That way you'll end up with a minimum amount of macro-generated code and fast compilation time.

Known issue with Scala Repl

In Scala Repl the Resolver could fail to resolve the requested service due to the issue with Scala Repl. To eliminate it try to perform the Resolver instantiation and the dependency resolution in two separate Scala Repl statement executions, like this:

val resolver = Resolver(FooProvider :: HNil)

hit "Enter"

val bar = resolver.resolve[Bar]

hit "Enter"


Cableguy is a very young project and it is not tested in production yet (at least by its creator :)). Nevertheless it has good test coverage and, because it performs dependency resolution compile-time, most of the possible issues should appear during the compilation phase.


First of all, the existing code base (especially macros implementation) should be cleaned up and made less cryptic. Also, it would be useful to introduce some resolution tracing logic to inform the end user why something could not be resolved or why it is resolved that way and not another.