When we implement DI via Reader, we make a dependency a part of our method signature. Assume we have (without implementations):
trait Service1 { def f1:Int = ??? }
trait Service2 { def f2:Reader[Service1, Int] = ??? }
type Env= (Service1, Service2)
def c:Reader[Env, Int] = ??? //use Service2.f2 here
Now, f2
needs additional service for implementation, say:
trait Service3
type Service2Env = (Service1, Service3)
//new dependecies on both:
trait Service2 { def f2:Reader[Service2Env, Int] = ??? }
It will break existing clients, they cannot any longer use Service2.f2
without providing Service3
additionally.
With DI via injection (via constructor or setters), which is common in OOP, I would use as a dependency of c
only Service2
. How it is constructed and what is its list of dependencies, I do not care. From this point, any new dependencies in Service2
will keep the signature of c
function unchanged.
How is it solved in FP way? Are there options? Is there a way to inject new dependencies, but somehow protect customers from the change?