Closure (computer programming)


In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

History and etymology

The concept of closures was developed in the 1960s for the mechanical evaluation of expressions in the λ-calculus and was first fully implemented in 1970 as a language feature in the PAL programming language to support lexically scoped first-class functions.
Peter Landin defined the term closure in 1964 as having an environment part and a control part as used by his SECD machine for evaluating expressions. Joel Moses credits Landin with introducing the term closure to refer to a lambda expression with open bindings that have been closed by the [|lexical environment], resulting in a closed expression, or closure. This use was subsequently adopted by Sussman and Steele when they defined Scheme in 1975, a lexically scoped variant of Lisp, and became widespread.
Sussman and Abelson also use the term closure in the 1980s with a second, unrelated meaning: the property of an operator that adds data to a data structure to also be able to add nested data structures. This use of the term comes from mathematics use, rather than the prior use in computer science. The authors consider this overlap in terminology to be "unfortunate."

Anonymous functions

The term closure is often used as a synonym for anonymous function, though strictly, an anonymous function is a function literal without a name, while a closure is an instance of a function, a value, whose non-local variables have been bound either to values or storage locations.
For example, in the following Python code:

def f -> Callableint], int]:
def g -> int:
return x + y
return g # Return a closure.
def h -> Callableint], int]:
return lambda y: x + y # Return a closure.
  1. Assigning specific closures to variables.
a: Callableint], int] = f
b: Callableint], int] = h
  1. Using the closures stored in variables.
assert a 6
assert b 6
  1. Using closures without binding them to variables first.
assert f 6 # f is the closure.
assert h 6 # h is the closure.

the values of a and b are closures, in both cases produced by returning a nested function with a free variable from the enclosing function, so that the free variable binds to the value of parameter x of the enclosing function. The closures in a and b are functionally identical. The only difference in implementation is that in the first case we used a nested function with a name, g, while in the second case we used an anonymous nested function. The original name, if any, used in defining them is irrelevant.
A closure is a value like any other value. It does not need to be assigned to a variable and can instead be used directly, as shown in the last two lines of the example. This usage may be deemed an "anonymous closure".
The nested function definitions are not themselves closures: they have a free variable which is not yet bound. Only once the enclosing function is evaluated with a value for the parameter is the free variable of the nested function bound, creating a closure, which is then returned from the enclosing function.
Lastly, a closure is only distinct from a function with free variables when outside of the scope of the non-local variables, otherwise the defining environment and the execution environment coincide and there is nothing to distinguish these. For example, in the program below, functions with a free variable x are executed in the same environment where x is defined, so it is immaterial whether these are actually closures:

x: int = 1
nums: list =
def f -> int:
return x + y
map
map

This is most often achieved by a function return, since the function must be defined within the scope of the non-local variables, in which case typically its own scope will be smaller.
This can also be achieved by variable shadowing, though this is less common in practice, as it is less useful and shadowing is discouraged. In this example f can be seen to be a closure because x in the body of f is bound to the x in the global namespace, not the x local to g:

x: int = 0
def f -> int:
return x + y
def g -> int:
x: int = 1 # local x shadows global x
return f
print
  1. prints 1, not 2

Applications

The use of closures is associated with languages where functions are first-class objects, in which functions can be returned as results from higher-order functions, or passed as arguments to other function calls; if functions with free variables are first-class, then returning one creates a closure. This includes functional programming languages such as Lisp and ML, and many modern, multi-paradigm languages, such as Julia, Python, and Rust. Closures are also often used with callbacks, particularly for event handlers, such as in JavaScript, where they are used for interactions with a dynamic web page.
Closures can also be used in a continuation-passing style to hide state. Constructs such as objects and control structures can thus be implemented with closures. In some languages, a closure may occur when a function is defined within another function, and the inner function refers to local variables of the outer function. At run-time, when the outer function executes, a closure is formed, consisting of the inner function's code and references to any variables of the outer function required by the closure.

First-class functions

Closures typically appear in languages with first-class functions—in other words, such languages enable functions to be passed as arguments, returned from function calls, bound to variable names, etc., just like simpler types such as strings and integers. For example, consider the following Scheme function:

; Return a list of all books with at least THRESHOLD copies sold.

)
book-list))

In this example, the lambda expression appears within the function best-selling-books. When the lambda expression is evaluated, Scheme creates a closure consisting of the code for the lambda expression and a reference to the threshold variable, which is a free variable inside the lambda expression.
The closure is then passed to the filter function, which calls it repeatedly to determine which books are to be added to the result list and which are to be discarded. Because the closure has a reference to threshold, it can use that variable each time filter calls it. The function filter might be defined in a separate file.
Here is the same example rewritten in JavaScript, another popular language with support for closures:

// Return a list of all books with at least 'threshold' copies sold.
function bestSellingBooks

The arrow operator => is used to define an , and an Array.filter method instead of a global filter function, but otherwise the structure and the effect of the code are the same.
A function may create a closure and return it, as in this example:

// Return a function that approximates the derivative of f
// using an interval of dx, which should be appropriately small.
function derivative

Because the closure in this case outlives the execution of the function that creates it, the variables f and dx live on after the function derivative returns, even though execution has left their scope and they are no longer visible. In languages without closures, the lifetime of an automatic local variable coincides with the execution of the stack frame where that variable is declared. In languages with closures, variables must continue to exist as long as any existing closures have references to them. This is most commonly implemented using some form of garbage collection.

State representation

A closure can be used to associate a function with a set of "private" variables, which persist over several invocations of the function. The scope of the variable encompasses only the closed-over function, so it cannot be accessed from other program code. These are analogous to private variables in object-oriented programming, and in fact closures are similar to stateful function objects with a single call-operator method.
In stateful languages, closures can thus be used to implement paradigms for state representation and information hiding, since the closure's upvalues are of indefinite extent, so a value established in one invocation remains available in the next. Closures used in this way no longer have referential transparency, and are thus no longer pure functions; nevertheless, they are commonly used in impure functional languages such as Scheme.

Other uses

Closures have many uses:
  • Because closures delay evaluation—i.e., they do not "do" anything until they are called—they can be used to define control structures. For example, all of Smalltalk's standard control structures, including branches and loops, are defined using objects whose methods accept closures. Users can easily define their own control structures also.
  • In languages which implement assignment, multiple functions can be produced that close over the same environment, enabling them to communicate privately by altering that environment. In Scheme:

)
))
))
; prints "none"
; prints "meet me by the docks at midnight"

  • Closures can be used to implement object systems.
Note: Some speakers call any data structure that binds a lexical environment a closure, but the term usually refers specifically to functions.