What is the ideomatic way to perform automatic dep...
# announcements
m
What is the ideomatic way to perform automatic dependency injection in functional Kotlin code? At the moment, most of my code is very java-like where it contains bunch of classes that contain business logic and dependencies between those classes are resolved with Dagger's constructor injection. Top level functions are mostly used as utility functions. This works fine, but it seems like Kotlin promotes a pattern where code is instead moved from classes into top level functions that cannot have dependencies easily injected (without passing everything manually of course). One practical example is with coroutines. Convention dictates that functions launching new coroutines should be declared as extension functions of
CoroutineScope
. This practically requires such functions to reside on top level, since calling member extension functions of other classes is very awkward in Kotlin. But on the other hand, I fail to see how to properly handle dependencies in top level functions. * For example if I have
Downloader
class that has
CoroutineScope.startDownloading
method, I can inject every dependency of the downloader easily via constructor, but calling
startDownloading()
is awkward (I need to call it via
with (downloader) {startDownloading())
statement). * On the other hand, if I just create
CoroutineScope.startDownloading()
top level method, it would be easy to call, but I would have to provide dependencies with every single call to that method, which would create messy code.
s
1) Functional and pure 2) Injected objects and impure code You get to pick one
👍 1
m
okay, but how do you handle dependencies with functional then?
manually pass them every time function is called?
s
Most of our logic is in classes so we pass it in the constructor. That includes what would otherwise be called a top level function like
Instant::now
.
s
Yup, manually, except for the ones that model side-effects (objects on the end-of-world).
Take a look at the FP library called Arrow and how you can do DI using FP constructs
(IO, Reader, Kleisli)
👍 1
m
thanks, will check that out
c
Reader
is a worse form of DI in all respects. I’d argue it’s not even dependency injection, it’s dependency passing, which only covers a subset of what DI actually enables.
j
i was under the impression we got a bit of a break from DI by having mix-in functions and such things as coroutine scopes to make a strong case for context assembly by scoping with early type checking.