Closure Exercises
You can use this JavaScript playground to run these examples.
Add this at the top and keep it there:
let print = console.log
Deferred execution
One common use of closures is to specify something now that needs to run later.
JavaScript has a setTimeout function that causes some code to run after a delay. (This one of the oldest dynamic features offered by web browsers. The function dates back to the mid-1990s.)
What will this print? In what order do the three print statements happen? Why?
print("1. Running...");
setTimeout(() => { print("2. I was delayed") }, 1000); // milliseconds
print("3. Done.");
The setTimeout could wait until the time has elapsed before letting the program proceed. This is called a blocking function: something that blocks further program execution until some potentially time-consuming thing has happened. If it works this way, the order will be 1, 2, 3.
However, setTimeout could be a non-blocking function: it could schedule the closure to execute later, but then allow the program to proceed immediately. If it works this way, the order will be 1, 3, 2.
Which is it?
What will the following code print? Think first, make some guesses, then run it:
print("Running...");
for (let i = 0; i < 5; i++) {
let delay = Math.round(5000 * Math.random());
print("Delaying by " + delay)
setTimeout(() => { print("I was delayed by " + delay) }, delay);
}
print("Done.");
Does reordering the print and the setTimeout here change the output? Why or why not?
print("Running...");
for (let i = 0; i < 5; i++) {
let delay = Math.round(5000 * Math.random());
setTimeout(() => { print("I was delayed by " + delay) }, delay);
print("Delaying by " + delay)
}
print("Done.");
Partial execution
Another common use of closures is to run a process one step at a time. A function can do some work now and then return a closure that will do the rest of the work later — maybe after some user action, or after some time-consuming operation like a database access.
Here is a function that builds a story one step at a time:
let story = (petType) => {
print(`Once there was a ${petType}.`);
return (petName) => {
print(`The ${petType}'s name was ${petName}.`);
return (food) => {
print(`${petName} ate ${food}.`);
print(`THE END`);
}
}
}
Study this code’s structure. Now, a challenge: how can you call the story function above (without changing its implementation at all!) so that it prints a full story?
Hint: What does the story function return? Another function. And what does that function return? Yet another function!
Here’s one way to do it:
let catStory = story("cat");
let fuzzyStory = catStory("Fuzzy");
fuzzyStory("spaghetti");
Here’s another approach:
story("cat")("Fuzzy")("spaghetti");
You probably won’t want to write code that looks like that on a regular basis! This approach, however, is very useful: we can run part of a task now, let other code run, then run more of the task later. Many languages and libraries use something like it, either explicitly or internally.
What happens if we don’t follow through on the chain of all three functions? What does this function call print, and what does it return?
story("guinea pig")
It prints Once there was a guinea pig. and it returns a function that will ask for the guinea pig’s name.
We can thus reuse those intermediate steps:
let guineaStory = story("guinea pig");
let juniperStory = guineaStory("Juniper");
let oliveStory = guineaStory("Olive");
juniperStory("veggies");
oliveStory("hay");
juniperStory("a treat");
Currying
Let’s strip away the intermediate print statements from the code above:
let story = (petType) => {
return (petName) => {
return (food) => {
print(`A ${petType} named ${petName} ate ${food}.`);
}
}
}
This looks and behaves a lot like a function with three arguments. It’s just that instead of saying story("cat", "Fuzzy", "spaghetti"), we say story("cat")("Fuzzy")("spaghetti"). This technique of transforming a function that takes multiple arguments into a chain of functions that each take exactly one argument is called currying (after mathematician Haskell Curry). It might seem like a silly trick, but it’s shockingly useful and important. Whole mountains of programming are built from the rocks of currying.
Recall that a captured variable is a variable that is referenced inside a closure but declared outside of it. Consider that code above. What variables are captured? Three: petType, petName, and print. The food variable is a normal parameter. No other variables are referenced inside of a closure in that code.
A syntactic shift
It is very, very common for a closure to consist of only a single return statement:
let square = (x) => { return x * x; };
Javascript provides syntactic sugar for this. If you drop the { curly braces }, then you don’t need the return either; you get a closure that returns the result of a single expression:
let square = (x) => x * x;
(Java provides this same sugar.)
Challenge: apply that sugar to this code:
let story = (petType) => {
return (petName) => {
return (food) => {
print(`A ${petType} named ${petName} ate ${food}.`);
}
}
}
Puzzle over it for a while! Once you think you’ve got it or find yourself stumped, here’s the solution:
let story = (petType) =>
(petName) =>
(food) =>
print(`A ${petType} named ${petName} ate ${food}.`);
…or you can put it all on one line:
let story = (petType) => (petName) => (food) =>
print(`A ${petType} named ${petName} ate ${food}.`);
That probably looks quite strange! It’s not: there are languages and styles of programming where that is what’s normal, and having multiple statements that execute sequentially is what’s weird. Yes, really. Gaze at that code for a minute, and start getting your brain used to the idea that the notation A → B → C looks totally normal. It is a curried function that takes A and then B and returns C.