If you have a function that returns a function, basically you need to rewrite things to lift the referenced state into the outer scope. In pseudo-C: (void -> int) incrementer(int initial_value) {
int count = initial_value;
return lambda() { return count++; }
}
might be rewritten as: struct hidden_environment_type {
int count;
}
int incrementer_lambda(hidden_environment_type *env) {
return env->count++;
}
void incrementer(hidden_environment_type *hidden_arg, int initial_value) {
hidden_arg->count = initial_value;
}
Now the caller will allocate a variable of type hidden_environment_type, and pass its address as the first (artificial) argument.Note that lambda functions require a different calling convention to C function pointers, since they need to be passed a pointer to their environment in addition to their regular arguments. Introducing lambdas either requires some resolution of this complication, such as specialisation machinery (ie in C++11, templates provide the necessary specialisation). Another option is to use the environment-passing convention for every indirect call, possibly giving a minor performance hit for calling raw function pointers. Another issue is that the size of an environment type depends on the code of a function involving it, so lambdas don't have uniform size unless some additional indirection is introduced, probably to heap storage (Apple's blocks extension to C takes this approach). This makes it either impossible or slightly more expensive to store lambda functions in data structures, depending on which implementation you choose. After all this, your ownership/lifetime question boils down to "who is holding onto the instance of hidden_environment_type?", which is a pretty simple question to answer in C-like languages. |