In the world of programming, it is inevitable to keep track of states, irrespective of the paradigm you use. There are, of course, a myriad of ways to accomplish this. For example, in mainstream object-oriented programming, states can be modelled as fields (in objects); in functional programming, states can be modelled in the form of closures.
I read a funny yet enlightening story a few years ago that gave me an epiphany.
The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said “Master, I have heard that objects are a very good thing — is this true?” Qc Na looked pityingly at his student and replied, “Foolish pupil — objects are merely a poor man’s closures.”
Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire “Lambda: The Ultimate…” series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
On his next walk with Qc Na, Anton attempted to impress his master by saying “Master, I have diligently studied the matter, and now understand that objects are truly a poor man’s closures.” Qc Na responded by hitting Anton with his stick, saying “When will you learn? Closures are a poor man’s object.” At that moment, Anton became enlightened.
Some code perhaps?
This is the typical way to simulate an object with some degree of encapsulation in a language that supports prototypical inheritance. However, did you know that you can achieve the same thing without using an object literal?
Now obviously I cheated a little and used the object literal in the
return statement. That is because I wanted to emulate the object literal’s behaviour to allow the caller to call
increment(). However, this still demonstrates the point of capturing states with two different methods:
- In the object example,
stateis modified via the
- In the closure example,
sis captured in closures created by the
sis not visible to callers outside of
Put it simply,
s’s scope is ‘extended’ to the point where future invocations of
increment can still get hold of
s latest value even though it has already gone out of scope.
Closures as a form of dependency injection
One very common question I get from people starting to learn functional programming is ‘How do we do dependency injection?’ Indeed, having dependencies injected for you is an important technique to manage complexity, as it is close to impossible for the human brain to mentally keep track of all database access, logging, authorisation, business logic, mappings in a non-trivial system at all times. Languages must provide some mechanisms to tame the complexity by abstracting details from the policy.
Interfaces (with constructor injection), most commonly associated with OOP, is a widely known technique to achieve policy–detail decoupling. One benefit of having dependencies injected means you can ‘assume’ the injected component is performing its job correctly and you only have to focus on your component at hand.
In functional languages such as F ♯, there is another way to achieve the same goal. Here is an example: the
findPlayerNames function ‘accepts’ a
dbConnectionString parameter as a dependency.
Due to automatic currying of F♯ functions, this actually creates a closure around
dbConnectionString, the equivalent manually-curried version would be:
That means the composition root can be responsible for ‘injecting’ a connection string into
The technique is called Partial Application, which takes advantage of currying and makes use of closures to emulate dependency injection in OO languages. There are also other FP techniques such as the Reader monad, but that is outside of the scope of this article.
Closures are not without their problems though, especially when mutability is increased into the equation. In fact, one of the very first articles I wrote on Medium is exactly about the dangers of capturing variables inside closures. I highly suggest you read that article as a follow-up.
A closure to closures
Given the recent language design trend of adopting FP concepts to OO languages, I think most readers having a few years of programming experience would already be using closures without even realising it. But, as programmers, it is important to understand the language mechanism you have been utilising in order to progress. This is especially true when the language you use doesn’t warn you from capturing variables in closures.
If you still don’t get what closures are, don’t worry. I didn’t get mine even though I know what closures are.
The only closure you would get, is the one you give yourself. — Who cares who said that