I am trying to understand how closures could be implemented in a language like C.
Currently I want to create an adder
function that takes an int
, and returns another function that also takes an int
param. Invoking the returned function should result in the sum of the two parameters.
Here's the pseudocode example:
fn adder(int lhs) {
return fn (int rhs) {
return lhs + rhs
}
}
Since nested functions are not available in standard C, I thought I could implement them by passing states. Here's my C implementation:
#include <stdio.h>
typedef struct
{
int *a; // This attribute should be a pointer as in my
// ideal interpretation of closures, the state of
// the parent function should be mutable within the child
} ClosureState;
int adder_inner(ClosureState state, int b)
{
printf("a = %d\n", *state.a);
return *state.a + b;
}
ClosureState make_adder(int a)
{
ClosureState state = {
.a = &a};
return state;
}
int main()
{
ClosureState adder_state = make_adder(5);
int res1 = adder_inner(adder_state, 5);
int res2 = adder_inner(adder_state, 10);
int res3 = adder_inner(adder_state, 50);
printf("%d, %d, %d\n", res1, res2, res3);
return 0;
}
The problem: The adder_state
object seems to be modified after every invocation of adder_inner
but I don't understand why as *state.a
is never reassigned.
The output of the code above is:
$ clang -o clj clj.c && ./clj
a = 5
a = 10
a = 50
10, 20, 100
There is no reason for ClojureState
(ClosureState
) to hold a pointer. It will be much easier if it just holds the int
itself:
#include <stdio.h>
typedef struct
{
int a; // No need for a pointer, the value can still be
// changed in adder_inner() if needed.
} ClosureState;
int adder_inner(ClosureState *state, int b)
{
printf("a = %d\n", state->a);
return state->a + b;
}
ClosureState make_adder(int a)
{
ClosureState state = {
.a = a};
return state;
}
int main()
{
ClosureState adder_state = make_adder(5);
int res1 = adder_inner(&adder_state, 5);
int res2 = adder_inner(&adder_state, 10);
int res3 = adder_inner(&adder_state, 50);
printf("%d, %d, %d\n", res1, res2, res3);
return 0;
}```