Most of the examples of the Cake Pattern I've come across appear to consider dependencies as singleton type services; where there is only one instance of each type in the final assembly of components. Is it possible to write a configuration that has more than one instance of a particular type, perhaps configured in different ways, when using the Cake Pattern for dependency injection?
Consider the following components. Generic HTTP service:
trait HttpService { def get(query:String):String }
trait HttpServiceComponent {
val httpService:HttpService
class HttpServiceImpl(address:String) extends HttpService {
def get(query:String):String = ...
}
}
Trade & Company services, that each depend on an HttpService, which may be different instances:
trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
this:HttpServiceComponent => // Depends on HttpService
val tradeService:TradeService
class TradeServiceImpl extends TradeService {
def lastTrade(symbol:String):String =
httpService.get("symbol=" + symbol)
}
}
trait CompanyService { def getCompanySymbols(exchange:String):String }
trait CompanyServiceComponent {
this:HttpServiceComponent => // Depends on different HttpService instance
val companyService:CompanyService
class CompanyServiceImpl extends CompanyService {
def getCompanySymbols(exchange:String):String =
httpService.get("exchange=" + exchange)
}
}
Main app component that depends on Trade & Company services:
trait App { def run(exchange:String):Unit }
trait AppComponent {
this:CompanyServiceComponent with TradeServiceComponent =>
val app:App
class AppImpl extends App {
def run(exchange:String) =
companyService.getCompanySymbols(exchange).split(",").foreach(sym => {
val lastTrade = tradeService.lastTrade(sym)
printf("Last trade for %s: %s".format(sym, lastTrade))
})
}
}
Is it possible to wire up the App so that its TradeService uses a HttpService that points to one address, and its CompanySerivce uses a different HttpService instance pointing to another address?
As you can see from the answers (notably Daniel's, but also your own), it is possible, but it doesn't look elegant. The difficulty appears because when you use the Cake pattern, you mix all required traits into one object (using "with" keyword), and you cannot mix a trait more than once into one instance. That is how mixins work, and the Cake is based on them.
The fact you can force Cake to handle non-singleton dependencies doesn't mean you should do it. I would advise you to simply use plain-old constructor in such cases, that is where self-type annotation doesn't fit well:
trait HttpService { ... }
/* HttpServiceImpl has become a top-level class now,
* as the Cake pattern adds no more value here.
* In addition, trait HttpServiceComponent gets deleted */
class HttpServiceImpl(address:String) extends HttpService {
...
}
trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
// The dependency on HttpService is no longer declared as self-type
val tradeService:TradeService
// It is declared as a constructor parameter now
class TradeServiceImpl(httpService: HttpService) extends TradeService {
def lastTrade(symbol:String):String =
httpService.get("symbol=" + symbol)
}
}
trait CompanyService { def getCompanySymbols(exchange:String):String }
trait CompanyServiceComponent {
// Again, self-type annotation deleted
val companyService:CompanyService
// Again, the dependency is declared as a constructor parameter
class CompanyServiceImpl(httpService: HttpService) extends CompanyService {
def getCompanySymbols(exchange:String):String =
httpService.get("exchange=" + exchange)
}
}
The App and AppComponent traits stay in their original form. Now you can use the all components in the following way:
object App {
def main(args:Array[String]):Unit = {
val appAssembly = new AppComponent
with TradeServiceComponent
with CompanyServiceComponent {
// Note, that HttpServiceComponent it neither needed nor mixed-in now
val tradeService = new TradeServiceImpl(
new HttpServiceImpl("http://trades-r-us.com"))
val companyService = new CompanyServiceImpl(
new HttpServiceImpl("http://exchange-services.com"))
val app = new AppImpl
}
appAssembly.app.run(args(0))
}
}
Also, you may want do double-check if the Cake pattern is really best suited for your needs, as it is actually a complex pattern and dependency injection is only one part of it. If you use it only for DI, I would advise you to use a simpler solution. I've blogged about that here.
Since each "client" may need a different implementation, you could just parameterize the service.
trait HttpService { def get(query:String):String }
trait HttpServiceComponent {
def httpService(name: String):HttpService
class HttpServiceImpl(address:String) extends HttpService {
def get(query:String):String = ...
}
}
To be used like this:
trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
this:HttpServiceComponent => // Depends on HttpService
val tradeService:TradeService
class TradeServiceImpl extends TradeService {
def lastTrade(symbol:String):String =
httpService("TradeService").get("symbol=" + symbol)
}
}
The final mix would then do something like this:
trait AppComponent {
this:CompanyServiceComponent with TradeServiceComponent =>
val httpServices = Map( "TradeService" -> new HttpServiceImpl("http://trades-r-us.com"),
"CompanyService" -> new HttpServiceImpl("http://exchange-services.com"))
def httpService(name: String) = httpServices(name)
This compiles and runs as expected, but it leaves a lot to be desired:
object App {
def main(args:Array[String]):Unit = {
val tradeServiceAssembly = new TradeServiceComponent with HttpServiceComponent {
val httpService = new HttpServiceImpl("http://trades-r-us.com")
val tradeService = new TradeServiceImpl
}
val companyServiceAssembly = new CompanyServiceComponent with HttpServiceComponent {
val httpService = new HttpServiceImpl("http://exchange-services.com")
val companyService = new CompanyServiceImpl
}
val appAssembly = new AppComponent
with TradeServiceComponent
with CompanyServiceComponent
with HttpServiceComponent {
lazy val httpService = error("Required for compilation but not used")
val tradeService = tradeServiceAssembly.tradeService
val companyService = companyServiceAssembly.companyService
val app = new AppImpl
}
appAssembly.app.run(args(0))
}
}
Related
I'm tying to create a typesafe wrapper around lwjgl. Most importantly, I want it to be a compile time error to pass the wrong constants to a function, e.g. calling glEnable(GL_ARRAY_BUFFER). This whould be rather easy if it weren't for different contexts supporting different constants for the same function.
I figured I'd use type classes to model which constants can be passed to which function. I've got a solution but admittedly it's a bit ugly and fails to apply a certain implicit:
trait GlConst { val glConst: Int }
trait GlConstCompanion[C <: GlConst] { val instance: C }
class GlDepthTest private () extends GlConst { val glConst = GL_DEPTH_TEST }
object GlDepthTest extends GlConstCompanion[GlDepthTest] {
val instance = new GlDepthTest
}
class GlLineSmooth private () extends GlConst { val glConst = GL_LINE_SMOOTH }
object GlLineSmooth extends GlConstCompanion[GlLineSmooth] {
val instance = new GlLineSmooth
}
class GlArrayBuffer private () extends GlConst { val glConst = GL_ARRAY_BUFFER }
object GlArrayBuffer extends GlConstCompanion[GlArrayBuffer] {
val instance = new GlArrayBuffer
}
// type class for arguments to glEnable
trait GlEnableCap[T <: GlConst] extends GlConst
object GlContext33 {
implicit object GlDepthTestIsEnableCap extends GlEnableCap[GlDepthTest] {
val glConst = GlDepthTest.instance.glConst
}
implicit object GlLineSmoothIsEnableCap extends GlEnableCap[GlLineSmooth] {
val glConst = GlLineSmooth.instance.glConst
}
def glEnable[T <: GlConst : GlEnableCap](t: T): Unit = println(implicitly[GlEnableCap[T]].glConst)
}
object Test extends App {
import GlContext33._
implicit def constComp2Const[C <: GlConst](cc: GlConstCompanion[C]): C = cc.instance
// works
glEnable(GlDepthTest.instance)
// fails to apply implicit glConstComp2Comp
glEnable(GlDepthTest)
// fails intentionally
glEnable(GlArrayBuffer)
}
Is there a way to get the implicit to work? Or is there an even better way to wrap OpenGL's constants?
As a rule of thumb, don't use implicits if you don't have to.
In this case you can solve it just as well using only type bounds:
// Start writing your ScalaFiddle code here
val GL_DEPTH_TEST = 1
val GL_LINE_SMOOTH = 1
val GL_ARRAY_BUFFER = 1
trait GlConstCap
trait GlEnableConstCap extends GlConstCap
trait GlBufferConstCap extends GlConstCap
trait GlConst[C <: GlConstCap] { val value: Int }
object GlDepthTest extends GlConst[GlEnableConstCap] {
val value = GL_DEPTH_TEST
}
object GlLineSmooth extends GlConst[GlEnableConstCap] {
val value = GL_LINE_SMOOTH
}
object GlArrayBuffer extends GlConst[GlBufferConstCap] {
val value = GL_ARRAY_BUFFER
}
object GlContext33 {
def glEnable[T <: GlConst[GlEnableConstCap]](t: T): Unit = println(t.value)
}
object Test extends App {
import GlContext33._
// works
glEnable(GlDepthTest)
// fails to apply implicit glConstComp2Comp
glEnable(GlDepthTest)
// fails intentionally
glEnable(GlArrayBuffer)
}
Try it out!
Note: You might want to add contravariance to C in GlConst if you want to create deeper inheritance structures of GlConstCap.
I hope this helps.
I have a trait and a class that extends the trait. I can use the methods from the trait as follows:
trait A {
def a = ""
}
class B(s: String) extends A {
def b = a
}
However, when I use the trait's method in the constructor like this:
trait A {
def a = ""
}
class B(s: String) extends A {
def this() = this(a)
}
then the following error appears:
error: not found: value a
Is there some way to define default parameters for the construction of classes in the trait?
EDIT: To clarify the purpose: There is the akka-testkit:
class TestKit(_system: ActorSystem) extends { implicit val system = _system }
And each test looks like this:
class B(_system: ActorSystem) extends TestKit(_system) with A with ... {
def this() = this(actorSystem)
...
}
because I want to create common creation of the ActorSystem in A:
trait A {
val conf = ...
def actorSystem = ActorSystem("MySpec", conf)
...
}
It's a little bit tricky because of Scala initialization order. The simplest solution I found is to define a companion object for your class B with apply as factory method:
trait A {
def a = "aaaa"
}
class B(s: String) {
println(s)
}
object B extends A {
def apply() = new B(a)
def apply(s: String) = new B(s)
}
This article explains Dependency Injection via Scala's Cake Pattern.
My understanding of this pattern's benefit is that traits can be mixed in (production v. test) with static checking.
In Mr. Bonér's example, he lists this finished (per example) code:
UserRepositoryComponent and UserServiceComponent
I added comments per my understanding.
trait UserRepositoryComponent {
val userRepository: UserRepository // stand-alone component
class UserRepository {
... // actual implementation here
}
}
trait UserServiceComponent {
this: UserRepositoryComponent => //Requires a mixed-in UserRepo*Component
val userService: UserService
class UserService {
... // actual implementation here
}
}
My understanding is that the Service depends on injection of a Repository component.
For production purposes, the following can be used to wire a "production" Repository component into the UserServiceComponent:
object ComponentRegistry extends
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
If our production code wanted to use the userRepository or userService, is the correct way to use them via a simple import?
I think that I understand half of the article up to this point, but I'm not sure how to use the ComponentRegistry object.
You're running head first into the bakery of doom bro:
What are some compelling use cases for dependent method types?
To answer your question, the proper way to use userService would be to use another trait and cake it up:
trait Example { this: UserServiceComponent =>
def getExampleUser() = userService.getUser("ExampleUser")
}
Now whatever this new trait does isn't directly coupled to anything like the object ComponentRegistry. Instead your application becomes this:
object Application extends
Example with
UserServiceComponent with
UserRepositoryComponent
{
val userRepository = new UserRepository
val userService = new UserService
}
Anyway, you should run for the hills because if you really want to use cake you should be doing something more like this:
trait UserRepositoryComponent {
type UserRepository <: UserRepositoryLike
val userRepository: UserRepository
trait UserRepositoryLike {
def getUserOrSomething()
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
type UserRepository = UserRepositoryImpl
val userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepositoryLike {
override def getUserOrSomething() = ???
}
}
trait UserServiceComponent {
this: UserRepositoryComponent =>
type UserService <: UserServiceLike
val userService: UserService
trait UserServiceLike {
def getUserNameById(id: Int): String
}
}
trait UserServiceComponentImpl extends UserServiceComponent {
this: UserRepositoryComponent =>
type UserService = UserServiceImpl
val userService = new UserServiceImpl
class UserServiceImpl extends UserServiceLike {
override def getUserNameById(id: Int) = userRepository.getUserOrSomething
}
}
trait Example {
this: UserServiceComponent =>
def getExampleUser() = userService.getUserNameById(1)
}
object Application extends
Example with
UserRepositoryComponentImpl with
UserServiceComponentImpl
Now save yourself some time, drop the cake pattern, and do something simple.
I'd like some help sorting out this scenario. I have an Akka actor where I want to inject a dependency, in this case RemoteFetcher, which I would also like mock in my tests. Like so:
main/src/scala/mypackage/Services.scala
package mypackage
import RemoteFetcherFileSystem._
trait RemoteFetcher {
def fetch( path:String ): Future[Stream[String]]
}
class MyRemoteResourceActor extends Actor with ActorLogging {
def fetchRemote( path:String ) = implicitly[RemoteFetcher].fetch( path )
def receive = {
case FetchRemoteResource( path ) => fetchRemote( path ).map( _.foreach( sender ! _ ) )
}
}
For this to work I have an implicit object that I import into the file above. Would look something like this:
implicit object RemoteFetcherFileSystem extends RemoteFetcher {
def fetchRemote( path:String ) = Future[Stream[String]] { ... reading from file system ... }
}
Now in my tests I have TestActor from the akka-testkit. Here I want to instead import my mock dependency:
implicit object RemoteFetcherMock extends RemoteFetcher {
def fetchRemote( path:String ) = Future[Stream[String]] { ... mock implementation ... }
}
My problem is that to compile Services.scala I need to import the implicit object. But how do I go about to shadow/override this in my test-files. The reason I'm not using implicit arguments is that I want to avoid having to modify all my actors constructor arguments.
I when looking around and reading up on the type class dependency injection pattern and I get it to work according to the tutorials, but I don't get it to work when I want to test and override like in my example.
I'm not sure how to do it with implicits, but typically one could inject instead like so:
trait RemoteFetcherComponent {
def remoteFetcher: RemoteFetcher
trait RemoteFetcher {
def fetch(path: String): Future[Stream[String]]
}
}
trait RemoteFetcherFileSystemComponent extends RemoteFetcherComponent {
val remoteFetcher = RemoteFetcherFileSystem
object RemoteFetcherFileSystem extends RemoteFetcher {
def fetch(path: String): Future[Stream[String]] = ???
}
}
class MyRemoteResourceActor extends Actor with ActorLogging with RemoteFetcherFileSystemComponent {
def fetchRemote(path: String) = remoteFetcher.fetch(path)
def receive = {
case FetchRemoteResource(path) => fetchRemote(path).map( _.foreach(sender ! _))
}
}
val myRemoteResourceActor = new MyRemoteResourceActor()
And then a test value would be defined like so:
trait RemoteFetcherMockComponent extends RemoteFetcherComponent {
def remoteFetcher = RemoteFetcherMock
object RemoteFetcherMock extends RemoteFetcher {
def fetch(path: String): Future[Stream[String]] = ???
}
}
val myMockedResourceActor = new MyRemoteResourceActor with RemoteFetcherMockComponent {
override val remoteFetcher = super[RemoteFetcherMockComponent].remoteFetcher
}
The reason you are having an issue with implicits is because the way you're using it is no different from simply using def fetchRemote(path: String) = RemoteFetcherFileSystem.fetch(path). With the import, you've defined the implementation, rather than allowed it to be injected later.
You could also change the implicitly to an implicit parameter:
trait RemoteFetcher {
def fetch(path: String): Future[Stream[String]]
}
object RemoteFetcher {
implicit val fetcher = RemoteFetcherFileSystem
}
class MyRemoteResourceActor extends Actor with ActorLogging {
def fetchRemote(path: String)(implicit remoteFetcher: RemoteFetcher) = remoteFetcher.fetch(path)
def receive = {
case FetchRemoteResource(path) => fetchRemote(path).map( _.foreach(sender ! _))
}
}
Then you could override the implicit that is resolved in the companion object of RemoteFetcher by simply importing RemoteFetcherMock.
See this post for more information about implicit parameter resolution precedence rules.
I'd like to reduce the boilerplate needed to bind these akka actors.
At current, my code looks like this:
bind(classOf[ActorRef]).
annotatedWith(Names.named("mines")).
toProvider(new TypeLiteral[ActorProvider[MyActor]]() {}).
asEagerSingleton()
I'd like it too look like:
bindActor[MyActor].withName("mines")
I've tried to subclass AbstractModule to squeeze this concept in to no avail.
Pertinent code:
class ActorProvider[T <: Actor] #Inject() ( val key:Key[T], val injector:Injector, val system: ActorSystem ) extends Provider[ActorRef] {
def get = {
system.actorOf(Props(injector.getInstance(key)))
}
}
Check out https://github.com/codingwell/scala-guice/. Here is a sample based on it. It allows for
bindActor[MyActor].withName("mines")
Keep in mind you are binding a non-generic ActorRef and not Actor itself. This will create a binding for #Named("foo") ActorRef. You should never work with Actor directly.
You cannot get Key in the provider. Provider doesn't take any contextual injections like you tried with the Key or e.g. Injection Point. What you can do is create a different instance of the provider for each actor binding and inject it with ActorSystem afterwards. Alternatively you could change the API to include the actor system instance aswell.
trait AkkaModule extends AbstractModule {
// should be:
// this: AbstractModule =>
// see http://lampsvn.epfl.ch/trac/scala/ticket/3564
import ScalaModule._
private def binderAccess = super.binder // shouldn't need super
def bindActor[T <: Actor](implicit m: Manifest[T]) = new ActorBindingBuilder {
//Hack, no easy way to exclude the bind method that gets added to classes inheriting ScalaModule
//So we experamentally figured out how many calls up is the source, so we use that
//Commit 52c2e92f8f6131e4a9ea473f58be3e32cd172ce6 has better class exclusion
val mybinder = binderAccess.withSource((new Throwable).getStackTrace()(3))
val self = (mybinder bind classOf[ActorRef]).asInstanceOf[AnnotatedBindingBuilder[ActorRef]]
}
}
object AkkaModule {
class ActorProvider(val name: String) extends Provider[ActorRef] {
#Inject var system: ActorSystem = _
def get = {
system.actorFor(system.name + "/user/" + name)
}
}
trait ActorBindingBuilder {
val mybinder: Binder
val self: AnnotatedBindingBuilder[ActorRef]
def withName(name: String) = {
val provider = new ActorProvider(name)
self.annotatedWith(Names.named(name)).toProvider(provider)
mybinder.requestInjection(provider)
}
}
}
Something like this that leverages scala's type Manifest might work
http://www.scala-lang.org/api/current/scala/reflect/Manifest.html
where Foo is analogous to ActorRef and Bla is analogous to MyActor:
scala> import com.google.inject
import com.google.inject
scala> val binder:inject.Binder = null
binder: com.google.inject.Binder = null
scala> class Foo {}
defined class Foo
scala> class Bla extends Foo {}
defined class Bla
scala> def bind[T <: Foo:Manifest] = binder.bind( classOf[Foo] ).toProvider( new
inject.TypeLiteral[inject.Provider[T]](){} ).asEagerSingleton
bind: [T <: Foo](implicit evidence$1: Manifest[T])Unit
Maybe combine that with implicit conversion to convert a Binder to a MyBinder:
http://daily-scala.blogspot.com/2009/08/implicit-methods.html
class MyBinder {
def bindActor[T <: ActorRef:Manifest]( nameToBind:String ):Unit = ...
}
object MyBinder {
implicit def binderToMyBinder( ...
}
Good luck!