Introduction to Programming Languages/Closures
Closures
editA closure is an implementation of a function, plus a table that binds values to the free variables that appear in the body of the function. A variable v is free in a function body f if v is used inside f, but it is not declared in f. Closures give the developer a way to pass functions around, together with some information about the context where these functions were created. Pragmatically speaking, closures allow the developer to write factories of functions. For instance, below we have a Python function that produces unary sums:
def unarySumFactory(a):
def unarySum(b): return a + b
return unarySum
inc = unarySumFactory(1)
print inc(2)
sum2 = unarySumFactory(2)
print sum2(2)
In the above example we notice that variable a is free in the body of function unarySum
. This variable has been declared in the scope of the function unarySumFactory
, and the fact that it can be referenced inside unarySum
poses to language designers an implementation problem. Normally once a function returns its value, the space reserved for its activation record is deallocated. However, if this space is deallocated, variable a in our example would no longer have a storage location once unarySumFactory
had returned a value. To circumvent this difficulty, closures are implemented as pairs (f, t), where f is a pointer to the implementation of the function, and t is a pointer to a table with all the free variables used in f associated with values.
Because the closure might outlive the function that has created it, normally the pair (f, t), and the contents of table t are allocated in the heap. The code below, written in C, implements the call unarySumFactory
seen before. C does not have syntactic support for closures. Nevertheless, we can implement closures by combining high-order function calls with dynamic heap allocation.
#include <stdio.h>
#include <stdlib.h>
typedef struct struct_free_variables_unarySum {
int x;
} FREE_VARIABLES_unarySum;
typedef struct {
FREE_VARIABLES_unarySum* t;
int (*f)(FREE_VARIABLES_unarySum* t, int x);
} CLOSURE_unarySum;
int unarySum(FREE_VARIABLES_unarySum* t, int y) {
return y + t->x;
};
void* unarySumFactory(int x) {
CLOSURE_unarySum* c = (CLOSURE_unarySum*) malloc (sizeof(CLOSURE_unarySum));
c->t = (FREE_VARIABLES_unarySum*) malloc (sizeof(FREE_VARIABLES_unarySum));
c->t->x = x;
c->f = &unarySum;
return c;
}
int test(int n) {
CLOSURE_unarySum* c = unarySumFactory(2);
int retVal = c->f(c->t, n);
free(c->t);
free(c);
return retVal;
}
int main(int argc, char** argv) {
printf("%d\n", test(argc));
return 0;
}