A few years ago I was trying to explain to a Java programmer what closures were and after listening to me, he merely replied “I’d use an object for that”. After he started working with Python, he began to change his mind after encountering Python’s somewhat limited lamba expressions. Once you understand closures, they become an indispensable tool for making code smaller and more flexible, but trying to explain closures to someone is about as daunting as explaining objects to seasoned COBOL programmers.
The Sapir-Whorf hypothesis basically asserts that thought is constrained by language. Some have interpreted this to mean (incorrectly) that we cannot understand ideas that we do not have words for. However, it might be better stated that we have difficulty understanding ideas that we do not have words for. Programming languages support this hypothesis.
My friend did not understand closures because most of his work was with Java, Prolog and C (static variables don’t count). The notion of a function “closing over” its lexical scope was so completely foreign to him that he didn’t understand the utility of closures. His programming languages of choice did not give him the vocabulary to express a particular idea, so he considered that idea uninteresting.
Guido van Rossum takes a similar view regarding multi-statement lambdas and seems to mistakenly conclude that these are merely Rube Goldberg toys. Few self-respecting Ruby or Perl programmers who’s grown used to the flexibility and code simplification that closures provide would agree.
Yesterday, I read a curious Weblog entry by Gilad Bracha, the current maintainer of the Java language specification, about why Java will not have continuations. While he mentions potential security problems and how continuations would be difficult to implement, his primary argument seemed to boil down to “continuation-based Web servers are the main reason we’d have continuations and those are a flash in the pan”.
Frankly, my jaw dropped when I read that. He can’t be serious that the main reason for continuations is a particular breed of Web server, can he? If he simply argued that continuations would be very hard to implement in the Java model, I’d be OK with that, but picking a particular reason for them and then trying to shoot down that reason sounds an awfully lot like a straw man. However, I wonder if the main reason he doesn’t worry too much about continuations is the same reason Tim Bray doesn’t worry about continuations, he doesn’t find them idiomatic. That goes back to Sapir-Whorf: if your language doesn’t express a particular concept, it’s difficult to think about that concept.
If you’re not familiar with continuations, Dan Sugalski has a nice entry in his blog to explain them. Further, he also explains why Parrot uses a continuation passing scheme. Though it took some effort to get this to work, the exra effort up front saved a lot of time down the road. Continuations make tail-call optimization a breeze. It also makes handling calling context very simple. These provide performance benefits and make functional programming more, er, functional.
In the end, the biggest arguments against closures, continuations, curried functions and other ideas that many programmers aren’t as familiar with seems to boil down to the “syntactic sugar” argument. This false argument states that since this is merely different functionality, not new functionality, that it’s not really that important. My rebuttal is simple: loops are “syntactic sugar” as we can merely use conditional jumps to implement them (which is how they’re often implemented internally). Yet would most programmers be happy without while and for loops?
It’s astonishing how so many of us are at the cutting edge of technology, yet we often resemble Luddites.


Interesting you mention Ruby and Sapir-Whorf - have you seen
http://www.rubyist.net/~matz/slides/oscon2003/mgp00001.html
It's a presentation on Matz' design considerations when he created Ruby, and a lot of it was based on some of those ideas.
Dick, thanks for the excellent link to Matz' presentation. I hadn't seen it before and it's very interesting.
You are mixing together a lot of ideas that are historically connected via Lisp, but not technically connected. Python has closures, and has had them for many years. Python has a stunted syntax for creating unnamed functions (lambda); that doesn't really have anything to do with closures.
Continuations are something else entirely, and not related to closures at all. That's a tricky thing to talk about; closures are something that normal people make and work with, when given the tools. It's certainly a higher-level concept, but not outside the ability of the average programmer. Continuations are *not* something normal people make and work with, even given the tools. Continuations are a powerful feature that can be used to create many more accessible features; continuations themselves are not accessible.
Continuation-passing style as an implementation technique is actually a separate issue from supporting continuations in the compiled language. Sure, it makes supporting continuations easier (because they are already passed explicitly), but continuations can be implemented without doing CPS in the compiler. If you can afford to GC activation records, then CPS is certainly the easiest way to go.
Now I've implemented several toy-languages with continuations and I certainly miss them from time to time when doing Java, but I'm quite certain they won't make it into Java. It's not that easy to change the semantics of an existing language so radically, even if the implementation were trivial.
How should Java's try..finally work with continuations? Remember, any call can now return multiple times and in the hundreds of millions of lines of Java code written nobody has expected that.
Does Java's security model work in presence of continuations? If it doesn't, is it possible to change it in a way that doesn't break the expectations of existing code?
How should JNI work with in presence of continuations? With JNI you can call C code, which can call back to Java. Now you have C in the middle of your Java call stack. Should continuations be able to jump through the C code. How should the C code release its resources? What if there are multiple returns through the C?
So my take is that implementing continuations is trivial. It's just not the implementation part that is hard about them.
Perhaps I should also note that you can write your code in continuation-passing style in any language that has support for lexical closures (heck, even Java, though the syntax would make eyes bleed). Of course the language should also support tail-call optimization or your stack will blow up (now Java is out).
Continuation-passing style is a horrible way to write code, but has the advantage is that even if your language doesn't support continuations, you get them. Typically pure CPS is gibberish so you wouldn't use it, but a hybrid approach where you pass explicit success and failure continuations around could make nondeterministic algorithms easier to read. (See SICP for good examples of this.)
Should we really be surprised when we show a functional construct to a person trained in OOP that they dismiss it as not being useful? I do think Sapir-Whorf has something to do with how you think about programming and programming languages. If you are used to thinking in a particular language then changing from that language to another with a completely different set of basic assumptions is going to be confusing.
That being said, all constructs can reasonably be expressed in all languages (in the worst case, they reimplement Lisp in their language of choice). Therefore, we must assume that people coming from those languages can be taught different concepts. Furthermore, because we can get that functionality from any (reasonable) language, it seems we should try to make the leap of showing people different ways of thinking.
Lispers often talk about the moment they "get it." I haven't personally had this moment (yet?) because I started with Scheme in college - at that time I had only had my self-learned Java experience, which was only six or so months old. I hadn't learned a language well enough to have a Sapir-Whorf affect, I wasn't yet competent to do anything more than write Mine Sweeper as an applet (remember those days?). This "getting it" is when Lispers minds finally accept the concepts that functional programming offers.
This is not to say that functional is better or OOP is better, I don't want to get into that debate. I do want to get into the debate that there shouldn't be a debate between the two. They are both programming, they are both important, and they can live happily together (see Ruby @ http://ruby-lang.org for an example). Shouldn't we be teaching our students to think in both paradigms? Can't we all just get along?
I repeatedly see Sapir-Whorf used all over the place. The "theory" was discredited long ago. (I suppose Stephen Pinker's "The Language Instinct" is the most available background for this. Programmers have a different problem than natural language. They have to use words in just such a way that they represent a valid mathematical object of some kind, trivial or not. They have to find words and statements which are defined on machine structures by the formal language. This has nothing to do with Whorf's (mis) perceptions.
Could anyone point me to a good resource for learning how to do closures in Python? My searches haven't turned up anything beginer oriented.
Could anyone point me to a good resource for learning how to do closures in Python? My searches haven't turned up anything beginer oriented.
Whoops, sorry for the double-post, browser wasn't refreshing :-0
Just to clarify, python does support closures as inner functions, what it doesn't have are multiline anonymous functions.
you wrote: Yet would most programmers be happy without while and for loops?
Actually, Scheme, a language that has continuations, does not have a looping construct. Iteration (aka looping) if required, is done via tail-calls. I'm assuming the true masters of scheme (the guys who wrote the spec) don't miss looping constructs - or they'd be in there.
Actually Scheme has looping construct. It's called "do" (see http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-7.html#%_sec_4.2.4)
While it's true that there's a lot Scheme code that uses tail calls instead of "do" for expressing iteration, it doesn't have anything to do with the fact that Scheme also supports continuations. The important thing here is that Scheme supports tail calls.
Now there are several languages that don't have looping constructs at all, but Scheme is not one of them.
Ovid: Sam Ruby has a great intro to continuations.
Alan: Reports of the disproof of Sapir-Whorf may have been greatly exaggerated.
on the question of closures in python please read:
http://perl.plover.com/classes/fp/samples/slide016.html
http://perl.plover.com/classes/fp/samples/slide014.html
http://rafb.net/paste/results/p8fM1088.html
http://geekswithblogs.net/vagmi.mudumbai/archive/2005/09/01/51811.aspx#67848
http://ivan.truemesh.com/archives/000411.html
George Orwell was expressing the same idea in 1984.
Nice post.
Peter Ahe approach to "Self Types" in Java appears similar to Gilad Bracha's approach to continuations:
self types would be useful for a generic Object.clone(); we can't change clone(); so self types aren't useful... Perhaps I've missed something:
http://blogs.sun.com/ahe/entry/selftypes