Rob Norris
closures in c
Back in November 2005, I was learning alot about Javascript. I’d used closures (essentialy anonymous functions) in Perl for years without thinking about it, but the way Javascript scopes variables makes them not work quite the same, so I was suddenly forced to think about closures in more detail.
I had this on the old website and would probably have been content to let it die there, but for two things ellie did this week:
- She pointed the Rails IRC channel at it, and I just can’t ignore that kind of exposure.
- She dared me to make function currying work in C, and the two are related enough that they should be nearby.
So consider this use of closures in Perl:
@c = ();
for($i = 0; $i < 10; $i++) {
my $x = $i;
push @c, sub { print "x is $x\n" };
}
$_->() for @c;
Or the equivalent in Javascript:
c = [];
for(i = 0; i < 10; i++) {
var x = i;
c.push(function () { print("x is " + x) });
}
for(f in c)
c[f]();
The C version would look like this:
#include <stdio.h>
#include "closure.h"
int main(int argc, char **argv) {
closure c[10];
int i, x;
for(i = 0; i < 10; i++) {
CLOSURE_INIT(c[i]);
}
for(i = 0; i < 10; i++) {
CLOSURE_START(c[i]);
int x = i;
printf("x is %d\n", x);
CLOSURE_END(c[i]);
}
for(i = 0; i < 10; i++) {
CLOSURE_CALL(c[i]);
}
Compile and run:
% gcc -Wall -ggdb -o closure closure.c
% ./closure
x is 0
x is 1
x is 2
x is 3
x is 4
x is 5
x is 6
x is 7
x is 8
x is 9
closure.h
provides the magic:
#ifndef __CLOSURE_H
#define __CLOSURE_H 1
#include <ucontext.h>
typedef struct closure {
ucontext_t enter;
ucontext_t exit;
int inside;
} closure;
#define CLOSURE_INIT(c) \
c.inside = 0;
#define CLOSURE_START(c) \
getcontext(&c.enter); \
if(c.inside) { \
ucontext_t __closure_end;
#define CLOSURE_END(c) \
swapcontext(&__closure_end, &c.exit); \
}
#define CLOSURE_CALL(c) \
c.inside = 1; \
swapcontext(&c.exit, &c.enter); \
c.inside = 0;
#endif
I hope to be able to have an implementation of currying/partial application soon - got some great ideas already :)