Closure (computer programming)

technique for creating lexically scoped first class functions

In computer science, a closure is a function that has an environment of its own. In this environment, there is at least one bound variable (a name that has a value, such as a number). The closure's environment keeps the bound variables in memory between uses of the closure.

Peter J. Landin gave this idea the name closure in 1964. The Scheme programming language made closures popular after 1975. Many programming languages made after that time have closures.

Anonymous functions (functions with no name) are sometimes wrongly called closures. Most languages that have anonymous functions also have closures. An anonymous function is also a closure if it has an environment of its own with at least one bound variable. An anonymous function with no environment of its own is not a closure. A named closure is not anonymous.

Closures and first-class functions

change

Values may be numbers or some other type of data, such as letters, or data structures made up of simpler parts. In the rules of a programming language, the first-class values are values that can be given to functions, returned by functions, and bound to a variable name. Functions that take or return other functions are called higher-order functions. Most languages that have functions as first-class values also have higher-order functions and closures.

For example, take a look at the following Scheme function:

; Return a list of all books with at least THRESHOLD copies sold.
(define (best-selling-books threshold)
  (filter 
    (lambda (book) (>= (book-sales book) threshold))
    book-list))

In this example, the lambda expression (lambda (book) (>= (book-sales book) threshold)) is part of the function best-selling-books. When the function is run, Scheme must make the value of the lambda. It does this by making a closure with the code for the lambda and a reference to the threshold variable, which is a free variable inside the lambda. (A free variable is a name that is not bound to a value.)

The filter function then runs the closure on each book in the list to pick which books to return. Because the closure itself has a reference to threshold, the closure can use that value each time filter runs the closure. The function filter itself might be written in a completely separate file.

Here is the same example rewritten in ECMAScript (JavaScript), another popular language with support for closures:

// Return a list of all books with at least 'threshold' copies sold.
function bestSellingBooks(threshold) {
  return bookList.filter(
      function(book) { return book.sales >= threshold; }
    );
}

ECMAScript uses the word function here instead of lambda, and the Array.filter method [1] in place of the filter function, but otherwise the code does the same thing in the same way.

A function may create a closure and return it. The following example is a function that returns a function.

In Scheme:

; Return a function that approximates the derivative of f
; using an interval of dx, which should be appropriately small.
(define (derivative f dx)
  (lambda (x) (/ (- (f (+ x dx)) (f x)) dx)))

In ECMAScript:

// Return a function that approximates the derivative of f
// using an interval of dx, which should be appropriately small.
function derivative(f, dx) {
  return function(x) {
    return (f(x + dx) - f(x)) / dx;
  };
}

The closure environment keeps the bound variables f and dx after the enclosing function (derivative) returns. In languages without closures, these values would be lost after the enclosing function returns. In languages with closures, a bound variable must be kept in memory as long as any closure has it.

A closure need not be formed using an anonymous function. The Python programming language, for example, has limited support for anonymous functions but does have closures. For example, one way the above ECMAScript example could be implemented in Python is:

# Return a function that approximates the derivative of f
# using an interval of dx, which should be appropriately small.
def derivative(f, dx):
    def gradient(x):
        return (f(x + dx) - f(x)) / dx
    return gradient

In this example, the function named gradient makes a closure together with the variables f and dx. The outer enclosing function named derivative returns this closure. In this case, an anonymous function would work also.

def derivative(f, dx):
    return lambda x: (f(x + dx) - f(x)) / dx

Python must often use named functions instead because its lambda expressions may only contain other expressions (code that returns a value) and not statements (code that has effects but no value).[2] But in other languages, such as Scheme, all code returns a value; in Scheme, everything is an expression.

Uses of closures

change

Closures have many uses:

  • Designers of software libraries can allow users to customize behavior by passing closures as arguments to important functions. For example, a function that sorts values can accept a closure argument that compares the values to be sorted according to a user-defined criterion.
  • 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 Smalltalk's standard control structures, including branches (if/then/else) and loops (while and for), are defined using objects whose methods accept closures. Users can easily define their own control structures as well.
  • Multiple functions can be produced which close over the same environment, enabling them to communicate privately by altering that environment (in languages that allow assignment).

In Scheme

(define foo #f)
(define bar #f)

(let ((secret-message "none"))
  (set! foo (lambda (msg) (set! secret-message msg)))
  (set! bar (lambda () secret-message)))

(display (bar)) ; prints "none"
(newline)
(foo "meet me by the docks at midnight")
(display (bar)) ; prints "meet me by the docks at midnight"
  • Closures can be used to implement object systems.[3]

Note: Some speakers call any data structure that binds a lexical environment a closure, but the term usually refers specifically to functions.

References

change
  1. "Core JavaScript Reference Objects:Array:Filter". Archived from the original on 2008-04-05. Retrieved 2018-06-20.
  2. "Python Manual". Archived from the original on 2008-12-02. Retrieved 2008-11-24.
  3. "Scheme example".