4 ms·
Can someone give an example of how (automatic) dependency injection works in functional programming? This to me is the only real benefit of OOP, that I can jus
by 0xcoffee 4y ago
Can someone give an example of how (automatic) dependency injection works in functional programming?
This to me is the only real benefit of OOP, that I can just add another service into the constructor and not have to update call sites of other signatures which would happen if I passed everything as parameter arguments.
I work in Asp Net land, and most of my work is linking services together and not so much solving mathematical problems.
- withinboredom 4y agoYou pass a partially applied function. So, example of php: $f = fn($x) => f($x, …$deps); Then I can pass $f to whatever function with its dependencies satisfied. Edit: fixed example
- SebastianKra 4y agoI wonder: Is automatic DI even helpful? You save some lines of boilerplate but sacrifice control over the initialization-order and get a flat, messy, implicit dependency graph. The decision of what goes where must be made somehow. So you either do it through the type (eg. `@inject(MySuperSpecificServiceThatOnlyExistsOnceAnyways.self)`), or write provider functions. Isn't the second solution basically the same thing as doing it manually?
- kgeist 4y ago>I wonder: Is automatic DI even helpful? You save some lines of boilerplate but sacrifice control over the initialization-order and get a flat, messy, implicit dependency graph Initialization order doesn't matter if your services are stateless. At least in our codebase, all of them are stateless, as it greatly simplifies reasoning about concurrent code (both in-process and between servers). Yes, it's easy to end up with a very convoluted dependency graph under the hood, but I don't think it's a problem you really should care about. I mean, your code most likely already compiles to a very convoluted mess of machine code under the hood (with all the optimizations, ABI quirks etc.) and I doubt it matters to you much, as long as it does its job well and doesn't hinder your productivity. If you are talking about messy dependency graphs from the architectural standpoint (someone can easily add a dependency in the constructor without thinking about the consequences), we use deptrac for our PHP monolith which can validate your architecture is clean at build time [0] However, for our microservices written in Go, we decided to use manual DI to stimulate developers to prefer simpler design, otherwise our microservices could quickly turn into monoliths again. [0] https://github.com/qossmic/deptrac https://github.com/qossmic/deptrac
- valcron1000 4y agoI work with Haskell every day and this is something that I really miss from OOP. You can go with Tagless Final or Free Monads, and neither solution feels good enough.
- lgas 4y agoIs something like the reader monad + data-has[1] closer to dependency injection in Haskell? [1] https://hackage.haskell.org/package/data-has https://hackage.haskell.org/package/data-has
- dgb23 4y agoIn Clojure dependency injection is rare and typically explicit in some way or another. But the problem you describe does not happen as far as I understood it. Dependency injection in that sense is only used in the "impure" parts, at the edge of your program, to build up application state. A popular approach is using something like integrant, which describes dependencies as a plain data structure, which gets resolved as a dependency graph and calls into multimethods (polymorphic functions) that you provide to start/stop individual services or what have you. Another popular approach is to use something like mount, which is basically just a macro which you use to describe how a service is started or stopped. All the dependency stuff is simply resolved via Clojure namespaces. Both of these (and others) are done in a way so you can start/stop your whole app or parts of it, or just individual services in a REPL. Most of your code doesn't interact with these services, but gets called from them (functional core), so you typically don't need mocks or other such things in testing as your domain logic doesn't know anything about application state.
- BiteCode_dev 4y agoIn python: from functools import partial new_function = partial(yourfunction, the_injected_dep=the_value)
- DeathArrow 4y agoEven in C# you can do it without interfaces and constructor injection. You just pass a Func<X, Y>.