On Jul 6, 2007, at 6:28 PM, Michael FIG wrote: > (let ((bar 1) > (bot (lambda () > (set bar 3))))
Currently Jolt's lambdas are not closures. Local variables from enclosing contexts cannot appear free (and are simply out of scope, as you found out) within them. > How do I construct a closure in Jolt that can bind to variables that > are local to the function in which the closure was created? I'd like > this in order to implement a useful callback function (which modifies > the state of its lexical environment, regardless of its caller). I > don't want to use global variables due to multithreading concerns. Since Jolt is designed (at least initially) to be a replacement for C as the target language for Pepsi, the lack of free variables is not a serious deficiency. The back end just generates the same 'linked list of state arrays' code that the current C back end generates, and the initialisation of the state array argument is done in value[:...] methods before invoking the closure's function (see below for some clarifications). More generally, there are at least four possibilities. First, if you don't mind having a special calling convention for closures, create a tuple containing a function pointer (lambda) and the data it is supposed to operate on. Invoke all your closures using a function that calls the closure's function pointer, passing the closure's data as an argument. The data can be anything, including an array of 'free variables' or even a list of such arrays linked through their first element (this is actually pretty close to the way Pepsi implements blocks). Second, if you don't mind your closures having dynamic extent (i.e., all closures that refer to free variables are implicitly destroyed when the context that created them exits), you can create a trampoline on the stack by manually assembling a few machine instructions that call a given lambda function passing the addresses of the free variables of interest. This is probably doable but very tricky (and definitely not portable) in the absence of a stack allocator equivalent to alloca(). (An alloca() is, FWIW, on the to- do list.) Third, if you don't mind waiting, you could arrange (maybe by persuading me to do it) for the compiler to provide the second possibility for you automatically whenever it notices accesses to free variables. Fourth, if you want closures with indefinite extent and don't mind making the entire runtime dependent on the presence of a garbage collector, would be the third possibility but with the trampoline allocated in the heap rather than on the stack and the free variables collected together in a state array (iow, the first solution implemented automatically for you by the compiler with the fallout cleaned up by a GC). I'd love for someone to come up with a better solution for full closures in Jolt. My current plan, to go with something like the fourth possibility, brings a GC firmly into the list of indispensables and is almost certainly a severe compromise. Desiderata for a cool closure implementation would include: 1. Closures look like functions (you can call them from statically- compiled C programs just like a pointer-to-function). 2. They accept arguments (even when passed from C code, without special precautions in that C code). 3. They look like objects too (you can send messages to them, in particular those of the 'value[:...]' variety). 4. They are cheap to instantiate and initialise. 5. They don't generate huge amounts of garbage. (I doubt that zero garbage is attainable, in a non-linear non-functional language, for closures of indefinite extent.) Cheers, Ian _______________________________________________ fonc mailing list fonc@vpri.org http://vpri.org/mailman/listinfo/fonc