Closures (programming)

From Helpful
(Redirected from Closures)
Jump to: navigation, search

This is about the programming concept, not one of the mathematical closures, physhological closure, or any other kind.


Definitions

Closures are easy enough to define in a technical way.

Say, Foldoc says "a closure is a data structure that holds an expression and an environment of variable bindings in which that expression is to be evaluated. The variables may be local or global."

...but harder to explain intuitively, or explain why and when they're interesting. So:

Explanation

In slightly more everyday terms, closures often mean a function that remembers (part of) the scope it came from, that it was defined in.


Consider the following pseudocode (it's javascript, but pretend you don't know whether it supports closures):

var add = function(a) {
  return function(b) {
    return a + b;
  }
}
var add10 = add(10);
 
//test it:
add10(5);   // 15, yay


Note that, in the first five lines,
a
is defined in the outer function's scope.

The inner function gets access to it because local/nested functions gets its own block scope, but also to see their parent's scope. It's half the reason such functions are useful.


But the above is apparently a language that allows you to return functions.

Those then needs to deal with the possibility that an inner function can get handed outside - as we've done. What would that do to the scopes involved, specificially, after you take that inner function out, what is a?

In a language that allows nested function but not closures would probably consider this invalid code, (the precise reasons would vary a little with how that languages thinks about with scope).


There's a few different options, and it's useful to work them out -- because it also makes you think about how scope works within simple execution models (local scope are stack-only and stops existing - efficient but inflexible) versus more flexible ones (scope are objects kept around - flexible but invites various issues).


In the latter, it turns out one of the more useful is to say that everything that is in scope while
add
was defined (and referenced within that inner function) will be available when you call
add
from anywhere else.


(You may notice that this is not the best example for when closures are useful. If the language supported function nesting but not closures, you could get around it by handing a into the inner function explicitly, thereby binding it into the inner function's scope. Not the cleanest solution if you have a lot of them, but certainly workable.)



Examples

JS/DOM use

Python use

Closures exist in python since 2.2.


One nice thing it allows is sorting an array-in-array structure by arbitrary columns, without having to hardcode for each specific case.

# That is, if you have a helper defined like:
def nth_lex(n):
    return lambda a,b: cmp(a[n],b[n])
#...then it allows:
matrixish.sort( nth_lex(2) )
 
# Instead of having to write:
matrixish.sort( lambda a,b: cmp(a[2],b[2]) )


There are a few caveats that defeats some of the possible uses.

The main one is that the enclosed scope is read-only. For example, in:

def foo():
    x='a'
    def bar():
        x='b'
    bar()
    print x

...you might expect it to assign and therefore print 'b', but bar's scope is foo's and is read-only.

You may expect it to either bork at runtime or create a variable local to it. It turns out it does the latter. But neither would be what you probably wwanted.

(This also implies another detail: If you want to do something like variable+=1, and that implies creating a new local variable, that may be functionally fine, but can imply you'll access it before trying to write it)


You can use python closures to support syntactic sugar such as:

def paid_more_than(amount):
    amount += 10 # ...cheapskate hack
    return lambda item: item['salary'] > amount
 
fair      = paid_more_than( 140 )
expensive = paid_more_than( 160 )
 
employees=[ {'salary':150}, {'salary':170,'isManager':True}, {'salary':120}  ]
print filter( fair,      employees )
print filter( expensive, employees )

fair and expensive are newly created functions (here via lambda because it's brief that way), and their variable 'amount' is based on the value that it had in its defining context - which is the respective executions of paid_more_than.

This makes them independent (no side effects, e.g. no outside alterations of amount is possible).

This also means you can use them in list comprehensions and generator functions (ignore them if you don't know them yet; think of it them as list creators-and-filters):

result = [e  for e in employees  if fair(e)]

Note that fair(e) is more or less like saying paid_more_than(140)(e), except that that would create a closure function every execution.


Since the non-generator/non-closured alternative to this is basically a function with a for loop, it's short through closures, though only if you actually use the paid_more_than thing regularly.

Of course, the above example is a little silly by being one-shot, as the for loop:

amount=140
for e in employees:
    if e['salary']>amount:
        print e

...is good enough.


Caveats

Easier memory leaks