I tried creating closures in C and I want to know how close to the mark I am.
First a few notes about what I did.
1. I used an example which hard coded the types for simplicity. I think you could generalize a solution with macros, it might be messy but I think its doable.
2. I assumed all data used in closures is allocated on the stack. Basically you have to keep the data valid after the donor function returns so it has to be allocated on the heap.
3. The closure just displays and increments the data.
Here's what I tried:
closure.h
Code:
#ifndef CLOSURE__HH
#define CLOSURE__HH
#include <stddef.h>
typedef struct closure* CLOSURE_PTR;
typedef void (*C_FUNC)(CLOSURE_PTR);
typedef struct closure {
int c_nu;//Basically a number(for debugging) to distinguish each closure
int data;//Value that the closure uses
C_FUNC call_closure;
} CLOSURE;
CLOSURE_PTR create_closure(int, int, C_FUNC);
void check_allocation(void*);
#endif
closure.c
Code:
#include <stdio.h>
#include <stdlib.h>
#include "closure.h"
void check_allocation(void * ptr) {
if (!ptr) {
fputs("Allocation failed!\n", stderr);
exit(EXIT_FAILURE);
}
}
CLOSURE_PTR create_closure(int c_nu, int data, C_FUNC f) {
CLOSURE_PTR c = malloc(sizeof(*c));
check_allocation(c);
c->c_nu = c_nu;
c->data = data;
c->call_closure = f;
return c;
}
main.c
Code:
#include <stdio.h>
#include <stdlib.h>
#include "closure.h"
void incr_it(CLOSURE_PTR c) {
if (c) {
fprintf(stdout, "Closure %d: %d\n", c->c_nu, c->data);
c->data++;
}
}
CLOSURE_PTR test_closure(int nu, int data) {
CLOSURE_PTR c = create_closure(nu, data, incr_it);
return c;
}
int main(int argc, char ** argv) {
CLOSURE_PTR c1 = test_closure(1, 12);
c1->call_closure(c1);
c1->call_closure(c1);
c1->call_closure(c1);
CLOSURE_PTR c2 = test_closure(2, 36);
c2->call_closure(c2);
c2->call_closure(c2);
c2->call_closure(c2);
c1->call_closure(c1);
c1->call_closure(c1);
c1->call_closure(c1);
c2->call_closure(c2);
c2->call_closure(c2);
c2->call_closure(c2);
return EXIT_SUCCESS;
}
Output:
Closure 1: 12
Closure 1: 13
Closure 1: 14
Closure 2: 36
Closure 2: 37
Closure 2: 38
Closure 1: 15
Closure 1: 16
Closure 1: 17
Closure 2: 39
Closure 2: 40
Closure 2: 41