Closures explained

A closure is a function which has captured ("closed over") one or more of the variables that were in scope when the function was defined.

There are several similar ways to implement closures. This is best understood by example. I will use pseudocode here.

Contents

Explicit capture

In some languages, you have to explicitly state which variables you want to capture.

Explicit capture by value

var x = "chips"

var more_spam = function () capture (x) {
    x = x + " and spam"
    print(x)
}

more_spam() // "chips and spam"
more_spam() // "chips and spam"

x = "bacon"

more_spam() // "chips and spam"

Notice how every invocation of more_spam begins with a variable x available, whose value is always "chips" at first. This is because we have captured x's value.

Meanwhile, the original x can be reassigned freely.

Explicit capture by reference

In a programming language which captures by reference, the same pseudocode yields different results.

var x = "chips"

var more_spam = function () capture (x) {
    x = x + " and spam"
    print(x)
}

more_spam() // "chips and spam"
more_spam() // "chips and spam and spam"

x = "bacon"

more_spam() // "bacon and spam"

Here, more_spam's x and the original x are the same variable; modifying one modifies the other. This is because we have captured x by reference.

Interestingly in this case, it's possible for x to drop out of scope even though more_spam hasn't and is still callable. When you call more_spam(), you will get the correct behaviour, because x still exists with its correct value, even though it is no longer directly accessible.

Note

Some languages allow you to select whether you capture by reference or by value, depending on which syntax you use when you declare the function.

Implicit capture

In some languages, the explicit capturing syntax doesn't exist. You just write:

var x = "chips"

var more_spam = function () {
    x = x + " and spam"
    print(x)
}

x = "bacon"

more_spam() // "chips and spam" if capturing by value
            // "bacon and spam" if capturing by reference

Here, more_spam captures x automatically, without being told. In fact, more_spam captures every available lexical variable, of which there could be many more beside x!

This can sometimes be problematic. If you want to use a variable named x inside your function, but you don't want to capture the x from outside it, you must remember to declare a brand new variable named x inside your function:

var x = "chips"

var more_spam = function () {
    var x = "more spam"
    print(x)
}

x = "bacon"

more_spam() // "more spam" every time

A classic pitfall

Use caution when creating closures in a loop. If you capture the loop variable by reference, watch what happens:

var more_food = {}

for var food in ["eggs", "chips", "spam"] {
    more_food[food] = function() {
        print("more " + food)
    }
}

more_food["eggs"]()  // "more spam"
more_food["chips"]() // "more spam"
more_food["spam"]()  // "more spam"

Here, all the closures have captured references to the same loop variable, food. After the loop is over, the value of this variable is "spam", no matter how it is accessed.

This gotcha is most often seen in JavaScript, but also appears in Python.

Back to Code
Back to Things Of Interest

Discussion (25)

2014-02-08 12:30:07 by qntm:

Every time I see people try to explain closures online, they do it using example code which is specific to one programming language (which not everybody necessarily understands), and example code involving multiple nested functions and multiple variables. Even if you do already know what a closure is/does, deciphering the code is not as easy as it should be. Here, I attempt to rectify this.

This is another article from the department of "putting things online in order to see if they're correct", by the way. If I've mis-stated anything here, I'd love to know what the real deal is.

Also, if you want to add a comment saying which programming languages fall into which categories, that would be great too.

2014-02-08 13:46:20 by hpc:

Perl captures everything by reference:

> my $x = 5;
> my $f = sub {
> print "out: $x\n";
> };
> $f->();
> $x = 6;
> $f->();
out: 5
out: 6

GHC captures by "reference", but that's an implementation detail since you can't observe it through mutation like in most other languages.

Common Lisp doesn't have a mechanism I know of to specify closing by reference or value. Variables are closed by reference same as Perl.

2014-02-09 03:39:15 by MHD:

Capturing behaviour is largely irrelevant in Haskells such as GHC.

I think I might be able to make a contrived example of it, but I have never had to think about it explicitly, given that mutation is largely impossible by design.

2014-02-09 10:39:28 by anonymouse:

I think part of why explanations get complicated is that this behavior isn't really interesting until you're in a scope where those variables that the closure captured are not available to you directly. And that requires either being in another module or in a higher scope than where those variables are defined. And for actual implementation, the case of returning a closure from a function is particularly tricky, but also particularly interesting, because it lets you do things like objects, or more general kinds of information hiding.

2014-02-11 17:42:02 by Redsplinter:

What gets really fun is when the language you're working in is capture-by-reference and the captured variable is modified inside the capturing function.

C# at least issues an "access to modified closure" warning, Python gives you an UnboundLocalError without the global declaration, but I'm not sure about any other languages. Intentionally used, it's a decent-but-odd way to do asynchronous state operations or a hacky way to do generators/etc..

Python example:
count_ = 0
def accum():
    global count_
    count_ += 1
    print("Accumulator call #" + str(count_))


if count_ == 0:
    print("Yep.")

accum()
accum()
accum()

if count_ == 0:
    print("Nope.")

Prints:
Yep.
Accumulator call #1
Accumulator call #2
Accumulator call #3

2014-02-11 17:43:37 by Readplinter:

Clearly I forgot to markup opening whitespace correctly above, apologies.

2014-02-12 14:54:31 by skztr:

I've never seen "capture by value". Can you list some languages which support this feature?

2014-02-12 15:05:52 by Moti:

@skztr:

C++11 is essentially an "all of the above" language, where a lambda expression can capture by value or by reference, implicitly or explicitly, and capture modes can be mixed for different variables in the same lambda.

Oh, C++. You are so zany and multi-paradigm.

2014-02-13 13:28:54 by Connor:

I understand it now. Yey!

2014-02-16 18:22:52 by qntm:

Skztr: it looks like I defined "capture by value" incorrectly. According to the revised definition, PHP captures by value by default.

2014-02-18 23:01:03 by Dentin:

Perhaps I'm getting old, or perhaps I just haven't worked on the right type of code, because every time I see closures explained or examples given I feel powerful sense of revulsion. It's as though everything in my experience is screaming at me, 'this is unmaintainable, confusing, and a recipe for disaster'.

Where would you ever use these things in real code, instead of using normal functions and properly lifetimed state variables? What are the problem domains that make the heaviest use of closures? So far the only real answers I've gotten revolve around event handler callbacks, which seem better done using something like the QT preprocessor.

2014-02-20 18:54:17 by Anon:

I agree with Dentin; how are closures even useful? Every use I can think for them would (in my mind, at least) be better by directly inputting a pointer-esque class thing. (I am definitely young, by the way)

2014-02-20 18:56:07 by Anon:

I don't know where to post this, by the way, but there is a serious issue with the new commenting system: The default color for the text is an off-white; the comment box's background is white; I can barely see the text I am typing, and need to constantly highlight it to read it.

2014-02-20 20:19:09 by qntm:

Anon, the background in the box should be the same dark blue as the site itself. That's what I see, anyway. Can you hit Refresh to make sure you have the new CSS which applied that particular style? If that doesn't work, let me know what browser you're using.

2014-02-20 22:09:55 by Dentin:

Anon, I can't say that closures should never be used. I've had some experience with Lua's anonymous functions, which are somewhat related, and I can see the value in them. However, I would also never even consider writing anything important in Lua; in that regard, it seems like a toy feature for a toy language.

On the other hand, a lot of people smarter than me have thought hard about closures, and they seem to think that it's an important language feature. There's got to be something to it, and there's got to be a handful of problem domains where closures are the 'natural' solution. I just don't yet understand what those domains might be.

2014-02-20 23:16:35 by Aegeus:

Closures are handy when you need to create a function on the fly for whatever reason. For instance, Wikipedia gives an example of creating a filter for an array.

I last used them in a GUI project in Python. I was creating a whole column of buttons which all did slightly different things, so I wrote a function that created the button, then created a lambda that connected to the button's event handler. So each lambda I created captured the information it needed for that particular button.

You could do this with objects (the Comparator interface in Java, for instance), but I think being able to just create the function you need is simpler.

2014-02-24 20:26:07 by Anon:

I'm using IE9. I really should not have expected IE to work with a random website.

Oh, so closures are used like lambdas? That makes sense. It's just that the code written above... looks like it would work more like a func(int* r) in C or something like that.

2014-02-26 11:50:27 by Veky:

People usually conflate lambdas and closures, probably because they solve similar problems (writing functions without too much bureaucracy), but they solve it in different ways. They are surely not the same.

Lambdas enable you to write a function without all the usual boilerplate of a prototype, and in languages where it matters, they are expressions, not statements, so they can fit into more language constructs.

Closures, on the other hand, enable you to write a function without specifying all the things your function might need as parameters, and just picking them up from surrounding scope when function is called (more often) or defined (less often).

Since people usually use both when they need just a quick & dirty function for something, they start to think there is some deep connection, or even worse, that they are the same. That's all.

2014-02-26 11:52:00 by frymaster:

white textbox in IE10 as well. This is probably because the page is not valid XHTML - I wouldn't expect browser consistency in this case.

2014-02-26 21:49:48 by qntm:

Actually, it appears that Internet Explorer doesn't implement the CSS "background-color: inherit" declaration correctly for form inputs.

2014-03-11 17:18:00 by testme:

<script>alert("xss")</script>

2014-03-11 19:15:47 by qntm:

Good effort. :)

2014-06-16 16:36:54 by Pipoca:

Anon and Dentin:

Closures aren't useful for only a few problem domains. They're useful when you use a functional style, and when you make heavy use of 'higher order functions' - functions which take other functions as arguments or return functions as results.

For example, suppose you have a list of points on a board, and you want to see if they're all empty. If you use a functional style, you could say something like

    allEmpty points board = all (map isEmpty points)
      where isEmpty point = getPoint point board == Empty

In that code, isEmpty is a function that closes over your local board variable, map is a function that applies a function to every element of a list, and all is a function that takes a list of bools and &&'s them all together.

Additionally, closures can basically implement objects - there's an old saying that "objects are a poor man's closure and closures are a poor man's object."

2014-07-04 09:51:52 by Coda:

I believe C++ supports both capture by value and capture by reference, based on the chosen syntax you use when declaring the lambda. (C++ only supports closures for lambdas; you can't define full functions inside other functions.)

2015-05-24 20:32:56 by anonymous:

JavaScript has implicit by reference but is possible to fake a capturing by value.

var x = "chips";
var more_spam = function () {
    x = x + " and spam";
    print(x);
};
more_spam(); // "chips and spam"
more_spam(); // "chips and spam and spam"
x = "eggs";
more_spam(); // "eggs and spam"

To make it a captured value you can make something like:

var x = "chips";
var more_spam = (function () {
    var y = x;
    return function () {
        var z = y;
        z = z + " and spam";
        print(z);
    };
})();
more_spam(); // "chips and spam"
more_spam(); // "chips and spam"
x = "eggs";
more_spam(); // "chips and spam"

Haskell is purely function without mutable variables therefore there is no difference between the difference kind.