Ask HN: How do you explain closures?

69 points by dstorrs ↗ HN
In the past year or two, I've had to explain closures--what they are and why they are interesting--several times. Usually, at the end of my explanation, the person doesn't get it, and they go back to doing whatever they are familiar with.

So, I ask HN to put yourselves in this scenario and tell me what your answer would be:

Joe is a talented but inexperienced developer. He's got a year or two of experience, maybe as much as 5, but he programs for a job, not for fun. Also, for whatever reason he's never encountered closures--most likely he's only worked in languages that don't really support them.

You want to explain to him (a) what they are and (b) why he would want to use them. You have about 10 seconds to get his interest before he starts thinking about his WoW raid tonight, and about 5 minutes for the whole explanation.

What do you say?

71 comments

[ 3.1 ms ] story [ 149 ms ] thread
An interesting demonstration of why closures are useful is to start from a hypothetical language that supports closures but not objects and then implement a (simple!) object/class system. For me, it was extremely clarifying to have something in my mind click and go "Oh, OOP doesn't need to be a language feature ... there's this much more powerful concept available as a building block."
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.

(comment deleted)
You have much to teach us, great one.
The idea is really nice, but I'm not sure it would work on the OP's Joe, who probably wouldn't even care about the hypothetical language and would regard the whole concept hypothetical, only for those who have way too much free time. (With WoW on the table, you don't have that luxury.)

I would take the route of first order functions -> anonymous functions -> closures, but I think it is really a lost cause for the typical 9-5 programmers.

I would take the route of first order functions -> anonymous functions -> closures

But those are three completely different concepts. A closure need not be anonymous or even first-order.

Yes. This approach works. I used it when I actually did work in a proprietary language which had no usable objects, but did have half-decent lambdas. Most people did not understand or use them at all, but one new guy with a Java background asked me how to cope. I explained to him how to use closures to implement a simple bank account class, and he got it immediately.

I don't think this guy played WoW, though. :)

I've found that the concept of anonymous functions is the biggest hurdle to get over -- closures seem to follow as a natural extension of that.

I explained this to someone recently in the context of event handlers in ActionScript/JavaScript, starting with the idea that when you do:

  something.onclick = function(){...};
you're passing a function around just like it was any other value.

Then I moved to an artificial example of a 'magic function-making machine':

  function giveMeAnAdder(baseNumber) {
    return function (i) {
      return baseNumber + i;
    };
  }
with a couple of examples of storing and using the functions that giveMeAnAdder returns.

Then I pointed out that, normally, local variables in a function disappear when the function returns, so how does my adder 'remember' what baseNumber is? And the answer is that the anonymous function is actually a bundle of a function body and the local context, and we call this a closure.

Thanks, this looks like a good way to present it. Next time I'm in this position, I'll use this as my jumping off point for the discussion.
This is my approach as well. JavaScript provides a very natural syntax for it, and the use case of "make me an event handler with some stuff baked into it" is extremely obvious and prevalent.
Can people please stop using the "make adder" examples? Can't you come up with something original and fresh? The triviality of what is acomplished in such case actually obscures the usefulness and power of the concept. As a result, the novice will interpret the end product as some useless, magical mambo jumbo that doesn't give him much. So who cares if I can get a function that adds a number to something. I have a "+" for that. Give me a use case that I can admire...

Why do you want me to appreciate a ferrari if all you do with it is go pick up some groceries...

That's why I use a counter as a simple demo - you see state changing with each call and it's done without using a global or passing in some kind of context object. It's not a lot more powerful than the adder, but in my experience it more often generates a "what the hell..." kind of reaction to the uninitiated.
I agree that for a novice a trivial example doesn't inspire them to learn more. But an experienced programmer who just wasn't familiar with this concept might appreciate more a stripped-down example like this that demonstrates the essentials of the idea. And in general, different people have different learning styles.
"Original and fresh" is generally not conducive to understanding. People are more likely to understand a new concept when that new concept is applied to concepts they already understand. It lets them filter out everything but that concept.
I usually go with a simple counter-generator as a first example:

  function counterMaker(next) {
    var value = next;
    return function() { value++; return value }
  }

  var myCounter = counterMaker(42);
  alert(myCounter());
  alert(myCounter());
  alert(myCounter());
I'm not sure it is necessary to explain what they are/how they work right at the start. An example like this is pretty clear that something "weird" is going on and if "Joe" is interested at all, questions should probably come up which can then be answered with more details. I think the "what to use them for" stuff is going to depend quite heavily on the environment, language, libraries, and product you're working on.

I usually find it's better to introduce a language idea to someone and let them try to find out where they might put it on their own - they may surprise you. If you're doing code reviews, you could use that as an opportunity to point out how something like a closure (or any other construct) might have improved a situation, or, at least, how it may have changed it.

(comment deleted)
Closures are functions with state.

Your claim that Joe is a talented programmer isn't very persuasive. Edit: maybe I should say why. I have known many programmers of the 9-5 type who do a passable job, but are not interested in learning anything. It is as if they had a limited supply of energy for learning and used it up when they were getting started. This is a common type of working programmer and you made it sound like Joe might be one.

A method remembers its context? I am not sure how to not understand it. Understanding all the implications might be another problem.
Closures are essentially a way to create private variables.

For example, in Javascript:

    var fn = null;
    
    (function(){
        
        var temporary = 789;
        alert(temporary);
        
        var secret_private = 5;
        fn = function(){
            alert(secret_private);
        };
    
    })();
    
    fn();

In javascript,

    (function(){ ... })();
defines and executes kamikaze function. It's a function which dies as soon as its job is completed.

We can use the kamikaze to hide secret_private from all but the functions that we want to have access to it.

Since fn is defined in the kamikaze function, fn can access secret_private.

Since fn is assigned to a global variable, it can be accessed from outside the kamikaze.

When the kamikaze dies, it takes all of its variables with it, except for the ones that are referred to outside of the kamikaze.

temporary disappears because it is referred to only inside the kamikaze.

But, since secret_private is referred to in fn, and fn is a global, secret_private does not disappear, but now only fn can refer to it.

So sceret_private is essentially a private variable of fn.

Kamikaze functions? Sounds dangerous...
I'm referring to all my anonymous functions from now on as kamikaze functions. Brilliant.
You could try an example showing what a closure does 'under the hood' by showing an equivalent non-closure example, like:

With Closure:

  foreach (var obj in objects) {
    AddButton("Delete " + obj.ToString(), () => obj.Delete());
  }
Without closure:

  class DeleteHandler {
    public DeleteHandler(TYPE obj) {
      _obj = obj;
    }
    private TYPE obj;
    public void DoDelete() {
      obj.delete();
    }
  }
  ...
  foreach(var obj in objects) {
    var deleteHandler = new DeleteHandler(obj);
    AddButton("Delete " + obj.ToString(), deleteHandler.DoDelete);
  }
I'm not convinced by the utility of your example. What's wrong with:

    foreach (var obj in objects) {
      AddButton("Delete " + obj.ToString(), obj.Delete);
    }
This is even simpler and doesn't use closures at all.
Doh!

It would have made more sense if I had some other piece of information to inject in, like if you had a database reference that needed to be passed in to the Delete() method.

Then:

  AddButton("Delete " + obj.ToString(), () => obj.Delete(db));
Vs.

  var d = new DeleteHandler(obj, db);
  AddButton("Delete " + obj.ToString(), d.DoDelete);
EDIT: fixed
Yup, makes more sense now! This is a good example, I think, to give to people who are used to objects being used for everything. Nice, clean, functional syntax.

(And of course you mean "d.DoDelete")

I implemented anonymous methods in Delphi, and I faced a similar kind of problem trying to sell them, as it were, to the Delphi community.

What they are: functions with state.

Why they're useful: callbacks where a whole separate method or class would be overkill.

Motivating examples:

* Delegating work to a background thread. Captured variables are an easy way to pass along necessary state.

* A generic benchmarking routine. Benchmarking requires taking a measurement before the code, running the code to be measured possibly multiple times, and taking another measurement after the code. If you can turn the code to be measured into a callback, then the benchmarking code can be written once and reused elsewhere. But having to put all your benchmarks into their own methods, much less worry about state and possibly creating classes and initializing data in constructors, is pretty tedious. Closures avoid this tediousness.

(Yes, I'm conflating several concepts here, anonymous functions and lambda closures, for colloquial and didactic reasons. Nitpicking doesn't buy you much in terms of practicality when learning here.)

Are they similar in any way to Python generators? They are functions with a state, at least.
Multiple closures can share the same state ("environment"). Consider:

  (let ((i 0))
    (list (lambda () (incf i))
          (lambda () (decf i))
          (lambda () i)))
If you evaluate the first function this form returns ("increment") and then the third form ("get"), the result is 1. If you evaluate the whole form again, you now have another "instance", with its own separate shared i.

In Python, you would probably just make this a class. (But sometimes it's nice to have something equivalent to a class that's automatically built for you, and closures are that something.)

(comment deleted)
(comment deleted)
(comment deleted)
(comment deleted)
A closure enables you to keep local state in a functional language. Think of it as an object (a really abused word, I know, but it conveys the idea).

So what are the mechanics? Follow me (I'll use Arc):

Lesson 1) A function can return a function:

  arc> (def adder-factory () [+ 1 _])
  #<procedure: adder-factory>
  arc> (= add-1 (adder-factory))
  #<procedure>
  arc> (add-1 10)
  11
Lesson 2) A created function can hang on to information which you pass in:

  arc> (def adder-factory (c) [+ c _])
  #<procedure: adder-factory>
  arc> (= add-17 (adder-factory 17))
  #<procedure>
  arc> (add-17 13)
  30
Lesson 3) The information a function hangs on to can be mutable local state.

  arc> (def make-point ((o x 0) (o y 0))
            "Constructor for creating point objects"
            (let methods (obj
                    get-x (fn () x)
                    get-y (fn () y)
                    set-x [= x _ ]
                    set-y [= y _ ])
                (fn (method . args)
                    (apply (methods method) args))))
  #<procedure: make-point>
  arc> (= pt (make-point))
  #<procedure>
  arc> (= pt (make-point))
  #<procedure>
  arc> (pt 'get-x)
  0
  arc> (pt 'set-x 17)
  17
  arc> (pt 'get-x)
  17
And that is a "closure". The name comes from the fact that the scope of the created function "closes over" the local variable.

Helpful or noisy?

I wrote this to answer that question: http://www.jerf.org/iri/post/2542

In particular, I focus on showing an example that is noticeably more complicated without closures, but also a real case that could conceivably come up.

(comment deleted)
Simple Clojure example:

  user=> (defn add-n [n] #(+ n %))
  #'user/add-n
  user=> (def add-2 (add-n 2))
  #'user/add-2
  user=> (add-2 5)
  7
They are functions you can make up on the spot. That's usually the extent of my explanation.

Surprisingly, most of the people I talk to assume that the "fancy" parts of closures (such as variable value capture and upvalues) are the way such a construct should work and require no further explanation to use them. People who are surprised by capture (and assume, for instance, that the variable will take on the most recent value assigned to it by outside code instead of "remembering the value when the closure was made") get a more lengthy computer science-esque explanation. But I generally find that explanation to be unhelpful if a person can't see why closures are useful; "An anonymous function with some teeth" is often how people I talk to come to closures first, so it's how I let them think about it until the model is no longer helpful.

Right. That's exactly how it was with me when I first encountered closures. Explaining something that would be guessed anyway just makes it seem more complicated than it is.
A lexical closure is similar in many ways to the class of an object-oriented language. In fact, lexical closures can be used to create an object system.

A class in PHP, for example, can have any number of class variables and for this demonstration consider these variables to be "private" (not accessible outside of the class or its own instances). One can, however, write methods or functions in the class that can provide an interface to operate on or access these private class variables.

That is, essentially, what a lexical closure is but without the overhead of an object system (remember, an object system can be created using closures!). They are a remarkably useful pattern of encapsulating certain kinds of logic.

Continuations, are another fun topic related to lexical closures too...

Closures are different from objects in only a couple of ways: (1) the creation protocol is extremely concise (lambda) (2) the access interface is the function call

Say that closures lower the syntactic overhead of accessing the same flexibility he normally turns to objects for.

So if he uses closures he will effectively use objects in more situations simply because it becomes easier and this will increase the flexibility of his code.

I wrote an article about the closure aspect of Ruby blocks that was intended for beginners:

http://darwinweb.net/articles/41-ruby_blocks_as_closures

It really focuses on just one aspect of closures that Ruby's syntax makes especially convenient, which is that they enable you to write generic functions that don't need to know a single detail about what kind of data they are being applied to.

Imagine you need a task to be done. Normally, you go and do it yourself. With a closure, you write the instructions and just hand it off to someone :)
Closures are functions that exist inside a variable. Therefore an entire different level of scope, now exists inside that variable. The variable then becomes like an object in that respect.

Easy.