If, like me, you’ve been doing object oriented programming for a while, you’ll be familiar with Dependency Injection. Dependency Injection is a form of Inversion of Control where a class’s dependencies are provided as constructor arguments. Here’s an example:
class Reporter { private readonly IReportRepository reportRepository; private readonly IReportSender reportSender; public Reporter(IReportRepository reportRepository, IReportSender reportSender) { this.reportRepository = reportRepository; this.reportSender = reportSender; } public void SendReportById(int id) { var report = reportRepository.GetReportById(id); reportSender.SendReport(report); } }
When we instantiate an instance of Reporter, we provide implementations of both IReportRepository and IReportSender. We then call SendReportById which executes methods on both of these dependencies. It’s a two stage process:
1. Create a Reporter with the dependencies it needs to do its job.
2. Execute the Reporter.
In a functional language like F# we can do the same thing without the overhead of having to declare classes and interfaces. We can also do the same thing in C#, but it requires some jiggery-pokery, so I’m going to show you it in F#.
let reporter reportRepository reportSender id = let report = reportRepository id reportSender report
Note: three lines of code verses nine for the C# version.
Here we’re defining a reporter function that takes three arguments, a reportRepository, a reportSender and an id. Internally it does exactly the same as our Reporter class above. In our object oriented version, we explicitly defined the dependencies as constructor arguments so that we can supply dependencies independently of executing the SendReportById method. But because functional languages support currying, we don’t need those constructor arguments, we can partially apply the function instead. We can call reporter with just the first two arguments to create a curried version of reporter that already has the reportRepository and reportSender dependencies satisfied. It’s then just waits for the last argument, the ‘id’ value, in order to execute.
If we execute this definition in F# interactive we see that it has this type:
val reporter : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
We can see that it takes two functions and a value and returns a value. We can also see that F# functions are curried by default. We can pass just the first two arguments (‘a –> b’) –> (‘b –> ‘c) and the return value will be ‘a –> ‘c.
Let’s define two simple implementations of reportRepository and reportSender:
type report = { id:int; title:string; body:string } let myReportRepository id = { id = id; title = "Great Report"; body = "The report body" } let myReportSender report = printfn "report = %A" report
New we can build a report sender that uses these two functions as dependencies:
let myReporter = reporter myReportRepository myReportSender
Now myReporter is equivalent to an instance of our Reporter class above. When we execute it, it’s the same as calling myReporter.SendReportById(someId):
> myReporter 10;; report = {id = 10; title = "Great Report"; body = "The report body";} val it : unit = ()
One could argue that the whole paraphernalia of object oriented programming is simply to make up for the lack of currying.
11 comments:
Thanks - I'm intrigued by the notion of using currying for DI, and more importantly I'm thrilled to add the phrase "jiggery pokery" to my arsenal.
Thanks Scott, pleased to be of service.
Mike,
You're confusing the term currying with partial application. Your point is spot-on though.
Here is something related http://blog.tmorris.net/i-have-found-that/
Thanks Tony, you are right of course. Currying is when you take a multi function argument f (x,y) -> z and turn it into a function that returns an argument f x -> (y -> z). In F# functions are curried by default. What I'm doing here is partial application.
Fogive my novice mistake, I'm still new to this FP lark.
This Lambda the Ultimate post was a great explaination:
http://lambda-the-ultimate.org/node/2266
Thanks for pointing me to your blog post. Most interesting.
I would say it is more like a closure. You create an environment in which things just are global, but you have control over how you setup that environment and can make multiple of those (running together in any configuration you like).
In javascript (hope the code is perserved somewhat):
function boot(logger, db, creditCardProcessor) {
Customer = {
creditCard: "xxxx-xxxx-xxxx-5090"
};
Cart = {
items = []
fetch: function() { db.get(request.session()) }
};
// ... lots of more objects functions and logic
return function(request) { run(request); }
}
boot(config.logger(), config.db(), config.ccp())(request)
well ... hope this sketches the idea. Preferably you start your whole webserver from withing the environment.
I think the equivalence should be
“Functional Dependency Injection == Parameter of Function or Interface Type”
This is less threatening to the OO programmer as it means you can be a little less radical in replacing beloved (and potentially valuable) named types with function types. It also lets you introduce them to the beauty of F# class types. e.g.
type Reporter(reportRepository: IReportRepository, reportSender : IReportSender) =
member this.SendReportById(id) =
let report = reportRepository.GetReportById(id)
reportSender.SendReport(report)
It is a separate step to replace named interface types with one "invoke" member by function types.
Onne,
It's not a closure, although you can use a closure to do a similar thing as you demonstrate. Closures are cool, but you only need to use them in your example because javascript does not curry functions by default like F#. Closures are more complex to create because you need two functions; the function that creates the closure (boot in your case) and the function that does the work.
Great example of a closure though :)
Anonymous,
FP is a very different way of thinking about programming. I'm an OO programmer. I'm curious about how FP works. This post is really just an expression of that curiosity. I understand OO programming and F# can do OO programming - well that's great, but what I really want to know is what all the FP fuss is about. So this post is more about FP than F#. I could just as well have used Java and Haskell to demonstrate the same thing.
Sure it's nice to show that F# is also a great OO language. But I wanted to show one way an OO programmer, like myself, can think of currying and partial-application as equivalent to a well known OO technique.
Silly enough, you could even partially apply printfn in your:
let myReportSender report =
printfn "report = %A" report
As in:
let myReportSender = printfn "report = %A"
Same diff
Nice explanation. Thanks.
My own definition (the one I say to myself to explain what's going on) would be:-
"Functional Dependency Injection == Passing a function to a higher-order function"
Thinking further on this:-
The act of dependency injection is passing a function to a higher order function.
If the higher order function takes only one argument, no currying takes place and partial application isn't possible.
When you do use partial application wrt dependency injection, it's only to create a function that bakes in one or more specific injected dependencies, as a convenience.
That's the way I'm seeing it.
Post a Comment