From dependency injection to dependency rejection by Mark Seemann
The problem typically solved by dependency injection in object-oriented programming is solved in a completely different way in functional programming.
Several years ago, I wrote a book called Dependency Injection in .NET, which was published in 2011. The book contains examples in C#, but since then I've increasingly become interested in functional programming to the extend that I now consider F# my primary language.
With that combination, it's no wonder that people often ask me how to do dependency injection in functional programming.
I've seen more than one answer, from other people, explaining how partial function application is equivalent to dependency injection. In a small series of articles, I'll explain both why this is true, but also why it's not functional. I'll conclude by showing a functional alternative to decoupling logic and (side) effects.
There's another school of functional programmers who believe that dependency injection in functional programming involves a Free monad.
You can often make do with less, though.
In my experience, it's usually enough to refactor a unit to take only direct input and output, and then compose an impure/pure/impure 'sandwich'. You'll see an example later.
This article series contains the following parts:
- Dependency injection is passing an argument
- Partial application is dependency injection
- Dependency rejection
- Pure interactions
The scenario is to implement an HTTP-based API that can accept incoming JSON documents that represent restaurant reservations.
The fourth article on pure interactions is a gateway to another article series on free monads.
I should point out that nowhere in this article series do I reject dependency injection as a set of object-oriented patterns. In object-oriented programming, dependency injection is a well-known and comprehensively described way to achieve decoupling and testability. In the next article, you'll see a brief review of dependency injection in C#.