This is the first in a series of posts that I’m writing about the concept of Closures in Functional Programming (FP for short) and how I related this concept to OO when I first came to FP and how my thinking on the concept has become more “Functional” over time.
When I started making the transition from OO programming to Functional Programming, the concept of a closure was one of the first functional programming concepts that I encountered. I found different explanations and definitions of what a closure actually is, some academic and formal and others more pragmatic. I have asked the question – what is a closure? – and have been asked this question during interviews and nearly everyone I discuss the concept with has their own take on it.
If you want formal definitions and explanations on closures, the google machine will give you a ton of them. In this series of blog posts, I want to leave formal definitions aside and show how I related the closure concept to OO programming at first, and how I refined and continue to refine my thinking.
My initial outlook – “closures are like inner classes”?
One way to think about closures when coming from OO, is to think about them in terms of inner classes “inheriting” property definitions from outer classes and, at runtime, “inner” object instances “inheriting” properties from the outer objects that created them.
Lets take a look at some OO Java code and translate this to functional Scala and then to Clojure code to show you what I mean. I will also explain the Scala and Clojure code along the way for anyone not familiar with these FP languages.
The Magic Jazz Band Closure
Lets model a Jazz Band that has a property for the tunes that it knows how to play called “setList”. Now, a jazz band isn’t a jazz band without musicians to play together. This is a magic jazz band though. If you want to add another Musician to it, it will simply just create one for you. This musician still needs to have a connection to the band though so it knows everything that musicians in the band should know – like what the set list is for the next gig!
This example is contrived and not the best way to model this type of thing in OO!
- This diagram illustrates a “Parent – Child” or “Outer Object – Inner Object” relationship between a jazz band called “theBop5” and a musician that the jazz band magically created called “tom”.
- Another way to describe this diagram is that it is a closure. The JazzBand “theBop5” instance “closes over” its state and has created “inner” state in creating Musician “tom”.
- Musician “tom” has access to the state of the outer instance “theBop5” that created it so “tom” knows what tunes they are playing.
- Musician “tom” is itself a closure too and any closures it creates will have access to its state and the jazz band closure’s state.
- As an aside, when I talk about “state” here, in a purely functional approach, this state should be immutable but I will go into more detail on that in later blog posts.
Set the Musician Free – He Needs to Practise!
Its fine for the jazz band to hold on to a musician that it creates so that the musician can play along with the rest of the band. However, musicians need time alone to practice the set list. The jazz band closure will want to be able to set the inner musician closure free but the the musician closure will still need a link back to its “parent” jazz band closure so that it knows the set list it needs to practice!
The following diagram demonstrates how this might work when thinking in terms of inner classes and objects.
OO Approach – Outer Objects Returning Inner Objects
In the Java example above, there is the outer Java class, JazzBand along with it’s inner class, Musician. At runtime, in the test case above, a new JazzBand object, theBop5, is created and it is used to create a Musician, tom. The Musician, tom, still has access to the outer object that created it after it has been returned to the test case function with the test asserting that Musician, tom, can access the setList of its outer JazzBand “parent” object and that this setList List object is indeed the same List object as the “parent” object.
FP Approach – Outer Closure Returning Inner Closures
Below is an implementation, in Scala, of the jazz band to musician relationship as an outer function( or closure) to the inner musician closure.
means we are defining a value, musicianFunctionThatCanGetBandSetList to be of type, a Function which takes no parameters and returns a list of Strings.
Function runtime values or “instances” can also be created using the same type of notation except, in this case, we declare the input parameters on the left side of the lambda expression and we declare the function execution on the right side of the lambda expression.
e.g a function to add 2 Ints could be expressed as follows:
The Int types are usually not needed here as Scala can usually infer Types from the context of the expression.
So, in the Scala example, we can see now that
is actually returning a function
Relating Outer-Inner Objects to Outer-Inner Closures Conceptually
The original diagram modelling the jazz band and musician as an outer to inner object, in an OO approach, and an outer to inner closure in an FP approach still holds true here. The difference in the FP approach is that we are modelling our magic jazz band, which can create musicians, as the outer function taking the setList as a parameter
and the inner musician who can still access the jazz band’s set list is returned from this function as an inner function which, on execution, returns the setList just like the
in the OO approach.
I know, the example is a bit contrived but it is deliberately so to show existing OO knowledge can be leveraged to understand the concept of Closures in FP. I am not claiming that functional programming languages necessarily implement closures like this under the hood; I am just hoping to provide an introduction to closures to developers who are more familiar with OO.
In further blog posts on this, I hope to explain further about closures in FP including things like lexical scoping and how closures can really be thought of more as execution contexts.
Also, this FP approach may seem limiting in that the outer function can only ever return an inner function which can only ever return the setList. This is because the example is modelling an OO approach using FP with closures so as to offer an introduction to closures for OO developers.
Really FP does bring with it a different way of thinking and solving problems. Instead of modelling functionality with objects that expose behaviour (like the JazzBand and Musician) which may or may not operate on encapsulated data structures; FP is all about pulling out those encapsulated data structures, making them immutable and operable on by any number of independent functions that know how to interpret the data structures. So the setList List data structure wouldn’t be encapsulated inside the JazzBand. Instead, it’s more likely that it would be a simple immutable list passed around to any number of functions each of which can operate on it and produce a new data structure as output which may or may not be a List e.g there could be a function addSong which would take the setList and produce a new list structure which would have song values matching the song values in the original setList along with an additional song.
To Finish: The Jazz Band closure implemented in Clojure!
Clojure is a personal favourite of mine for FP languages at the moment. It has great simplicity and elegance, but at the same time, it has all the power of FP.
Below is the Jazz Band to Musician outer-inner closure example implemented in Clojure.
I know for anyone new to Clojure, it can seem clouded with parenthesis. However, after a short time programming in Clojure, it is easy to start loving the parenthesis especially when you begin to see the consistency and simplicity in the Lisp language syntax. Also, a good IDE, like the Cursive plugin for Intellij, takes full advantages of the parenthesis – for example, on moving the curser to any parenthesis, it automatically highlights this parenthesis and its corresponding starting or ending parenthesis making it easy to examine and refactor blocks of code.
The Clojure implementation is conceptually the same as the earlier Scala implementation. The key to understanding the code is to know that, in Clojure, code is data – a parenthesis grouping is a list with the first element of the list being treated as a function and the remaining elements its parameters. This makes it very easy to identify our closures. In the test,
the outer jazz-band-that-creates-musician function (our jazz band closure) gets executed in the inner parenthesis grouping.
Like the Scala example, this returns a function representing a musician that returns the band set list when executed. This is our inner musician closure and gets executed because of the extra outer set of parenthesis in the clojure code. It’s like saying:
Also, to understand the function
a function is declared at compile time with the syntax
a function implementation can be defined at runtime in Clojure with the syntax
Thanks for taking time to read this blog. I will be following up with more blogs to help introduce FP concepts to developers who are more familiar with OO.