Dependency injection with Reader Monad in Scala

Compile time problem at run time

λ.eranga
λ.eranga
Jan 21 · 3 min read

Background

Monads are a category of data types. Informally, anything that has a type parameter, a constructor that takes an element of that type, and a flatMap method(which has to obey certain laws) is a Monad. Monads can wrap values, pass them between functions as a parametrized type and allows to perform operations on the values without unwrapping it. You can see some good introduction about Monad from this video. In this post I’m gonna discuss about using a special Monad type calledReader Monad which we can use for dependency injection. On my previous post I have discussed about using Scala Cake Pattern for dependency injection. We can get rid of third party dependency injection libraries and cake pattern boilerplate by using Reader Monad. So it called dependency injection without gymnastic. I’m using the Reader Monad implementation available in cats-effects library in Scala. All the source code which related to this post available in gitlab. Please clone the repo and continue the post.

Sbt dependency

I have used IntelliJ Idea as my IDE to work with Scala applications. I need to create sbt project and add the build.sbt dependency file with cats-core(it provides Reader Monad implementation)and other dependencies. Following is the build.sbt dependency file.

Dependencies

I have two repositories UserRepo and PermissionRepo. These are the main dependencies of the application. There is Repo case class which wraps these dependencies.

The repository implementations can interact with database or external HTTP API and do the relevant functions. In this demonstration I have built sample implementations of these repos UserRepoImpl and PermissionRepoImpl.

There is a handlers which use these functions and do user create, user search, permission search operations. These handlers take Repo as the dependency. I’m gonna discuss two ways to do dependency injection on handlers, Constructor Injection(or function arguments) and Reader Monad.

Constructor Injection

The default and easy way of doing dependency injection is with Constructor Injection(or function arguments). Following is the way to do the dependency injection with Construction Injection.

Following is the way to invoke these functions from main class. The repository dependencies are created here and pass them to functions as input parameter.

Reader Monad

The main concern of the Constructor Injection method is, the functions required Repo as its argument(e.g getUser() and createUser() required the Repo as a parameter). We can get rid of this input parameter in the function and are move it to the return type by using Reader Monad. When dependencies are injected at the top level, they have to be passed around from one function to another, regardless of whether or not any one particular function actually uses them. The Reader Monad lets us encode dependencies directly into the type, while providing composability(it provides map, faltMap like compassable functions).

Following is the way to do the dependency injection with Reader Monad. It warp functions with Reader where we can pass the Repo in run time. The return type of the function would be Reader[Repo, _]. The UserPermissionHandlerWithMonad class shows how to use composability with Reader Monad. It compose getUser and searchPermission functions with for expression. The normal Constructor Injection or other methods we cannot do this. That is power of monads.

Following is the way to invoke the monadic function from main class. The repository dependencies are created here and pass them to monadic functions with run() method(not via function arguments).

Reference

  1. https://earldouglas.com/posts/itof/di-to-reader.html

Rahasak

Have less, be more

λ.eranga

Written by

λ.eranga

Ego = 1/Knowledge

Rahasak

Rahasak

Have less, be more

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade