Dependency Injection w/ Reader Monad

267 views
Skip to first unread message

Chris Kahn

unread,
Jun 12, 2014, 11:17:41 AM6/12/14
to sca...@googlegroups.com
I've read a few threads on here, and a few of those posts reachable on Google, about using the Reader monad to achieve dependency injection in Scala. I find this approach really intriguing.

However none of these articles put up any sort of usable example code so I can examine what a functioning version would look like, and a lot of what I'm reading is too basic / fails to address a few real-world issues. The example is typically the database connection being injected into some class using the Reader monad. However, in my Cake-style applications, it's more than just a Connection object being passed around: I have a dependencies from Controllers -> Services -> Repositories defined using traits, with the concrete implementations of services and repositories being injected by controllers at the top of the application. Is there a nice, clean way to inject multiple dependencies down several layers around?

The second problem I have is that in the past I've used ReactiveMongo, and presently I'm using the postgresql-async driver. Thus my repositories return, for example, a Future[Option[User]] not Option[User], and I'm additionally confused about how to properly handle this.

Another problem I'm trying to solve is, in postgresql-async you can run multiple calls in a database transaction by calling connection.inTransaction and passing it a f: Connection => Future[A] which can be mapped to chain several operations in a transaction. I want to be able to have my service layer run multiple repository calls in a transaction without my service classes having to know about the specific database driver's inTransaction method.

Thanks for any help or advice.

Chris Marshall

unread,
Jun 13, 2014, 6:48:46 AM6/13/14
to sca...@googlegroups.com
Strictly speaking, you should be using an IO-like Monad to do your database code. But that's OK because you can use ReaderT[IO, Config]

Typically I would define something like (if I understand you correctly):

case class Config(controllers: Controllers, services: Services, repos: Repositories)

Then run your program thru Reader[Config, _]. If you do use ReaderT with IO, then it's useful to do something like this:

   type Program[+A] = ReaderT[IO, Config, A]

You can then define type constructors in a module:

  object Program {
    def point[A](a: => A) = .... 
  }

If you are interested, I gave a presentation recently about pretty much exactly what you are talking about here (except rather than use a Connection to access a database, I use a Session to get data out of a bespoke Java API). The last slides include using ReaderWriterStateT with Config, and threading errors thru \/ - and I also talk about what to do when you get Futures back from your API. The presentation is available http://www.slideshare.net/oxbow_lakes/fpx-talk-2014 and talk here: https://skillsmatter.com/skillscasts/4943-teaching-an-old-dog-new-tricks-wrapping-an-imperative-api-in-a-functional-one (you need to register for content).

Chris
 
  


--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalaz+un...@googlegroups.com.
To post to this group, send email to sca...@googlegroups.com.
Visit this group at http://groups.google.com/group/scalaz.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages