What the Cr*p is a Closure?

What the Cr*p is a Closure?

Anyone new to languages like JavaScript or ELISP may have a hard time understanding the concept of closures - and rightly so. Unlike the well understood paradigm of scope in Computer Engineering - the concept of a closure is disconnected from the actual hardware on your machine. It's a mathematical construct instead of a hardware usage optimization.

Scope

In languages like C and C++, the scope of a variable can be viewed as the lines of code in which that variable's reference exists. For example lets take a look at this simple C++ program:

#include <iostream>

const int NUM_ARRAY_SIZE = 10;

int main()
{
  int numbers[NUM_ARRAY_SIZE] = {1,2,3,4,5,6,7,8,9,10};
  for (int i = 0; i < NUM_ARRAY_SIZE; i++)
  {
    std::cout << "numbers[" << i << "] == " << numbers[i] << std::endl;
  }
}

As you may observe, in this example there are three variables, and each variable has a different level of scope. NUM_ARRAY_SIZE is a constant with a global scope (meaning that anywhere in the code we may reference that variable). numbers is an array with its scope bound to the main function (meaning that the only place we can reference it is inside the main function). The last variable, i, is a counter that has what we call block scope (meaning that this variable only lives while the for loop is executing).

Line of code What variables the Program Stack has in it
1 []
3 [NUM_ARRAY_SIZE]
7 [NUM_ARRAY_SIZE, numbers]
8 [NUM_ARRAY_SIZE, numbers, i]
10 [NUM_ARRAY_SIZE, numbers, i]
11 [NUM_ARRAY_SIZE, numbers]
12 [NUM_ARRAY_SIZE]

As soon as a scope is closed (delimited by { and }) associated variables are popped off the Program Stack and can no longer be referenced. This is to free up the memory on the stack for later use by the program.

I didn't come here to talk about Scope, I wanna know about Closures

The reason I brought up how scope works is so that we can understand how Closures are different. Closures, being a mathematical construct of Lambda Calculus, are not concerned with hardware; scope is. For scope, it's all about the state of the program stack.

In functional programming, everything is in a single scope - the scope of a function. And every function created inside a function has access to the variables of its parent function - all the way up to the global function (which most languages represent implicitly). We call these functional scopes "Closures."

Lets take a look at an example before I keep rambling

Though JavaScript is not a purely functional language, it has many aspects of functional style programming - including closures. In our example, we will use closures in JavaScript to create a Singleton Class.

Note: if you don't know what an IIFE is, quickly read about them before trying to understand my example. I tried to write this example as terse as possible.
const Singleton = (() => {
  let instance = null

  return class Singleton {
    constructor () {
      if (instance) return instance
      instance = this
    }
  }
})()

let singleOne = new Singleton()
singleOne.foo = "bar"

let singleTwo = new Singleton()
console.log(singleTwo.foo)       // > "bar"

The JavaScript engine will run this code block line by line. On lines 12 and 15, we use the new operator to invoke the Singleton's constructor. Here is the interesting thing. By the time we get to line 12, the IIFE used to define Singleton has already been executed. Since that IIFE is anonymous and we have no references to it, shouldn't the instance variable be gone too? How can the Singleton class still have access to the instance variable if exists "in the past"?

The answer - 🌈 Closures!

Because the definition of the Singleton class still has a live reference to it in memory, the JavaScript engine keeps all the closures that definition was a part of in active memory - including closures to functions that "have already finished executing." So in a way, you can look at closures as a transcendental scope since they can reference variables in past functions.

Closing thoughts

There are a lot of people much smarter than me who wrote better examples and go way more in-depth than I did (like MDN). I just wanted to share my understanding of closures. I use them all the time in Web Development. Hopefully this article helped.

If you have any questions, feel free to hit me up on Twitter. Or listen to our podcast here on detachedhead.net.