Welcome to the fourth episode of Functional Scala!
This time we’ll take a closer look at those all-around highly discussed Closures and try to clear some misunderstandings about it, since there are so many discussions out there, confusing simple Functions with Closures. In the first place, Closures are simply Functions featuring some special characteristics (which we’ll gonna talking about) turning them into, well … Closures.
As we’ve all gathered some profound knowledge about the definition and some of the characteristics of common Functions within the first three episodes, let’s not waste any more time and take a look at another example of a Function, which is intended to filter a list of given integer values by the first element within that list: all values less than the first element should be included within the result. Admitted, this Function isn’t that meaningful (and only works properly for non-empty lists), but it will serve as a good entrance into the world of Closures:
val belowFirst = ( xs : List[Int] ) => { val first = xs( 0 ) val isBelow = ( y : Int ) => y < first for( x <- xs; if( isBelow( x ) ) yield x } ... belowFirst( List( 5, 1, 7, 4, 9, 11, 3 ) ) // => List( 1, 4, 3 )
Wow, hold on, chap! What’s going on here? In fact, there are some new features within that example, so let’s try to understand the Functions inner machinery line by line:
Nothing new should turn up at line 3: it’s simply an expression where we refer to the first element of the given list by introducing an appropriate value declaration first. The type of that value must be an Int, since its an element out of a List of integer values (we leave that thrilling job to the compilers type inference capabilities). We’re now able to refer to the first element by using that alias name as the story continues …
Ok, one value declaration under the belt, another one at line 5. And now take a closer look. Can you spot the type of that value? Yep, it’s simply another (local) Function. We shouldn’t have any problems with that, since we already know, that a Function is an ordinary (first class) value and therefore nothing more, but also nothing less than any other values (like our value first of type Int). If you’re familiar with Haskell, you may think of that nested Function as defined within a where clause. Well, it turns out, that this local Function qualifies as our Closure, we’ll take a closer look in a moment.
In order to bring our inspection to an proper end, let’s take a look at line 7. What we have here is a so called list comprehension (we’re going to focus within another episode). For now, think of it as visiting every element within the ingoing list xs and decide which one may go into an outgoing list (as the resulting value of the whole comprehension expression), if it gets past that if-guard. Since that list comprehension represents the last expression within our function, it represents also the result of the Function.
Open Terms
You may became somewhat suspicious while you inspected that nested local Function. Let’s take it out of its context and take a closer look in isolation:
... val isBelow = ( y : Int ) => y < first ...
Didn’t we say, that a Function calculates its result solely in terms of its arguments? If so, what’s about that variable first (you know, not that kind of mutable variable as we think of it in an imperative language)? The only declared argument is y, so the use of y inside the Functions body is bound to that argument. And while there isn’t any other one, the use of first within the Function body is clearly not bound to an argument! Well, whenever you detect such a variable that isn’t declared as one of the Functions arguments nor introduced locally – congrats, you’ve found what it’s said to be a free variable.
And the story goes on: A Function containing at least one free variable is called an Open Term. In order to get to a fully functional Function, all free variables have to be bound (turning that open term into a closed term). For this to be done, the compiler reaches out to the so called lexical environment, in which that Function was defined and tries to find a binding. This process is called closing over which results in a closed expression or – for short – a Closure.
In the above example, the scope in which the local Function was defined is the nearest local part of the lexical environment. It’s the body of the surrounding Function. And within that scope, the free variable can be successfully bound to our value declaration of first, refering to the first element within the given list. But what if the free variable couldn’t have been bound to a value within the body of the surrounding Function? Well, than the Binding process wouldn’t have been completed. In this case, the compiler needs to expand the search for an appropriate Binding. But where to look for next? The arguments of the surrounding Function belong to the lexical environment, too. So a free variable within a closure could also be bound to an argument (which gives rise to some powerful abstractions, as we will see in some future posts. I have to mention the power of Closures especially in conjunction with higher order Functions here, since i’ve always mentioned higher order Functions so far). If there’s still no successful Binding available, the compiler closes over to the scope, in which the surrounding function was defined itself. So the following scenario would be completely legal:
val offset = 3 ... val below = ( barrier :Int, xs :List[Int] ) => { val isBelow = ( y : Int ) => y < barrier + offset for( x <- xs; if( isBelow( x ) ) yield x } ... below( 5, List( 5, 1, 7, 4, 9, 11, 3 ) ) // => List( 5, 1, 7, 4, 3 )
Ok, here we have two free variables barrier and offset within Function isBelow. And while barrier is bound to the first argument of the surrounding Function, the compiler has to close over to the outer scope in order to find a valid Binding for offset. All in all, not to scary any more – just a simple ordinary Closure!
Binding – values vs. variables
All is fine in functional world if a free variable binds to an immutable value. Since that value can’t change between multiple calls of the Closure, the Function can’t result into different values (given the same arguments), at least for the part which depends on the bound variable. And of course the other way round also holds: the Closure itself can’t change the bound variable and therefore can’t produce any side effect. So all in all, even a Closure is a pure Function if all of the values it operates on are immutable (or if there’s generally no idea of value assignment within the language).
But what about Scala? Since Scala offers mutable variables and therefore also value (re-)assignment of such variables, it depends on whether Scala provides a kind of static Binding, where free variables bind directly to an (immutable) value or rather a kind of dynamic Typing, where free variables bind to relative locations in memory that can store values (and the values in the bound location might change). Well, we can bring Scalas behaviour to light by starting a simple experiment:
var minAge = 18 val isAdult = ( age :Int ) => age >= minAge val isGermanAdult = isAdult( 20 ) // => true minAge = 21 val isUsAdult = isAdult( 20 ) // => false
I think you’re already in the position to clearly see what’s going on! Function isAdult seems to be a Closure since it contains a free variable minAge. The free variable is bound to the variable within the surrounding environment. Note, that minAge is declared as a mutable variable instead of an immutable value! And now take a closer look at line 7, where the value of that variable gets changed. It’s exactly between the two calls to our Closure isAdult which is applied to the same argumends twice. Rats! Our Function results into different values, based on the value change of the bound variable between the Function calls.
Now guess the kind of Binding. It must be dynamic, since a Closure behaves differently due to variable changes. The Binding doesn’t refer to the value, given at the time of Function definition but instead to the underlying location in memory. Again, Scala bite us due to the fact that it’s an hybrid object (imperative) functional language and therefore also allows for imperative constructs. Pertaining to the construction and usage of Closures, this means that we might walk into the trap again and produce some impure Functions.
Quintessence
So what’s the quintessence this time?
We saw that a Closure is some special kind of Function which refers to some free variables, bound to values within the surrounding lexical sope of the Function. ‘Well, then?’ you might wonder and ask: ‘Beside the fact that i now understand that most discussions essentially revolve around Functions in general, only partly about Closures’ what’s the big deal? I can’t give you a fully statisfying answer at this time. As you will see in some further episodes, Closures play a fundamental part in many different areas, ranging from simple state representation up to Monads (now you should wake up and pick notice, since Monads are so fancy these days and you might still impress your team members and friends).
And there’s another one, we discovered several times now: while Scala provides great freedom to go either an imperative or functional way, you might get into problems if you mix them up. As soon as you introduce state to your Functions or the environment in which your Functions are living in, as soon there’s a risk to end up with impure Functions. That’s what we should keep in mind: Of course, you might take advantage of all the options which may come with the blend of object oriented and functional concepts, but with greater freedom, there’s always also demand for greater discipline …
November 15, 2010 at 6:24 am
In line three of the first listing xs(0) will throw an exception for the empty list; better add a comment or use headOption.
November 15, 2010 at 6:59 pm
Thanks Heiko,
added a short note within the Functions introductory paragraph!
Grettings
Mario
November 15, 2010 at 10:23 am
Nice clarification of closures. I also like the deeper view into the compiler’s search for the binding of free variables.
May I suggest to switch age and barrier in line 3 of the second listing?
November 15, 2010 at 10:54 am
sorry I meant the forth listing.
November 15, 2010 at 7:03 pm
Lutz,
thanks for your feedback! Fixed that relation between age and barrier (now renamed to minAge for clearance) to the right direction.
Greetings
Mario
November 15, 2010 at 1:11 pm
This illustrates an issue with “hybrid” languages. If the language is missing features necessary to state compile-time proofs about that what we believe to be pure, then the hybrid nature of the language actually harms our ability to confidently engineer the benefits of FP into the software with that language.
November 15, 2010 at 9:58 pm
[…] This post was Twitted by scalaBin […]
November 17, 2010 at 7:20 am
thanks for this post really helps me a lot buddy
November 22, 2010 at 6:15 am
hello I was luck to search your blog in digg
your topic is exceptional
I get much in your website really thanks very much
btw the theme of you website is really splendid
where can find it
November 22, 2010 at 9:40 am
[…] Fourth episode […]
November 25, 2010 at 10:08 pm
Mario, thank you for the awesome Scala articles series. One question: what if a function belongs to an object and accesses that object’s state variables (vals or vars). Will this kind of function be a closure?
November 25, 2010 at 10:40 pm
Alexander,
first of all thanks for your kind and encouraging words!
Yep, that function would still be called a closure since it still includes a free variable, leaving the function as an open term. Hence, also in this case ‘Closing over’ takes place where the nearest surroundig scope of that function is the object it’s defined within.
The tricky thing in Scala is, that you’re free to declare variables beside of values. In the case that a closure refers to a mutable value it’s not free of side effects and therefore isn’t pure any more.
Greetings
Mario
November 26, 2010 at 8:29 am
Great! So that just means that a simple Java getter is a kind of closure?
December 2, 2010 at 8:20 pm
Replying to myself. No: according to “Programming in Scala”, function must be created at runtime to be a closure.
November 29, 2010 at 5:51 am
[…] it within a local function (we’ve already seen local functions while we’ve focussed on Closures), so we can refer to that local function afterwards within the comprehension’s guard. Again, […]
December 8, 2010 at 1:28 pm
Functional Scala: Closures « brain driven development…
Here at World Spinner we are debating the same thing……
April 19, 2011 at 2:37 pm
[…] Functional Scala: Closures […]
April 27, 2011 at 9:44 pm
Just a note… there appears to be a missing end-parenthesis in your 1st example on line 7. That is,
“for( x <- xs; if( isBelow( x ) ) yield x"
should be
"for( x <- xs; if( isBelow( x ) )) yield x"
Thank you for a great series of posts!
December 4, 2011 at 4:06 pm
[…] But wait, where come those values like x, y or even radSquare? Since those values aren’t defined as arguments of our resulting function, we have some free variables which only got bound by closing over into the lexical scope where the function is created (that is the body of our function maker, were we’ve calculated the square of the circles radius only once). So the delivered function must be a … tataaa … closure! […]
December 28, 2011 at 7:23 am
[…] been one of the touted advantages of Scala (see honorable mention section of this post for more on Scala‘s big year). Programming languages such as Haskell (or Jaskell on the JVM) and LISP (invented […]
December 28, 2011 at 1:21 pm
[…] been one of the touted advantages of Scala (see honorable mention section of this post for more on Scala‘s big year). Programming languages such as Haskell (or Jaskell on the JVM) and LISP (invented […]
May 9, 2013 at 11:45 pm
hh
August 7, 2013 at 2:41 am
[…] reading: Functional Scala: Closures […]
September 7, 2013 at 12:50 am
Great post!!! Thanks,