I watched Inception with friends last Saturday. I really enjoyed it and thought it was really well made, though it’s certainly a complex movie which you need to pay attention to. Considering that most of the readers of The ByteBaker are computer savvy (and probably programmers) you’re going to like it (or hate it) very much because it touches on some of our core concepts: recursion, closures and abstraction. In this way, it’s not all that much different from the Matrix — different premise and plotline but a very similar feel.
Without dropping any spoilers here’s what you need to know about the movie for the rest of the article: it’s about people who go into other people’s dreams in order to steal their secrets. Pretty simple, right? The kicker is that it’s possible to dream inside another dream leading to all sorts of interesting situations and plot twists. Ok, so that’s not quite recursion since that would mean that the subject would be dreaming the same dream inside the dream (confused yet?). Come to think of it the dreams of Inception are more like closures.
So what are closures? Wikipedia tells us that:
Perfectly understandable, right? No? Ok let’s translate. First and foremost, a closure is a function. But it’s not just any old run-of-the-mill function. A closure generally contains variables that are neither local variables nor arguments to that function. So what do those variables refer to? Their values come from outside the function, specifically the code block that surrounds the function. The wikipedia page on closures gives examples in a number of languages. Though closures aren’t necessarily a part of a standard curriculum they are extremely powerful constructs that can be used to implement a host of other programming language features (including control flow structures and object systems). Coming back to Inception, once you are inside a dream you can recall the world outside (though the real world seems like a dream so everything’s a bit fuzzy).
Closures in computer science (and dreams in Inception) are important because they are a prime example of abstraction. Functions are a powerful concept because they essentially let you create little worlds in which you can do stuff. You put something in a function and get something out. You don’t need to know or care about what’s going on inside the function (unless something goes wrong, but that’s a different matter entirely). Functions let you abstract away processes. Closures improve upon functions and let you abstract state. If you’re using a function that’s a closure, you don’t need to know about what it’s variables are bound to (except the ones you pass in) and you can’t see what data the closure can manipulate either.
By tucking away state, closures give us less to hold in our minds and make it easier to write code that’s clean and follows the Single Responsibility Principle (essentially, do one thing and do it well). Suppose you have a bunch of closures inside one larger function. Now magically you have sections of executable code that all operates on the same data and yet can do completely different things. They can also do all this without having to passing in a host of arguments every time (which reduces the chance for making mistakes). Whenever the closures need something, they just refer to their outer environment. Sound familiar? It should because I just described objects and methods. And that is the hallmark of a good abstraction — it lets you build up other abstractions on top.
Abstractions are in general a good thing. But unless you think through your abstractions, they can be bad. A leaky abstraction is one that doesn’t quite get it right. The underlying layers somehow “leak through” what should be the abstraction’s water tight boundaries. Joel Spolsky has a very good article on leaky abstraction that’s a must read if you want to learn more. And while we’re on the topic of abstraction — too much can be a bad thing. I wrote a Python program two summers ago to experiment with L-systems. Last summer I tried rewriting it such that everything in the system was the instance of some class. Everything was supposed to go through methods and abstraction boundaries. I never finished. This summer I toned it down a little and got a working version in about a week. Yes, this is classic second system effect, but it also shows that sometimes abstractions will just get in the way and force you to jump through hoops.
In conclusion: abstractions are good if used wisely. Closures are one such powerful abstraction. Dream safe.