Version 5 of Emulating closures in Tcl

Updated 2002-05-07 11:43:23

Some languages (like Lisp family, Smalltalk, Lua) contains an interesting feature called closures. Closure represents a block of code with surrounding context, whose execution is deferred. A block can be executed later (probably more then once) with old context and newly passed arguments.

Closures often used to provide customized behaviour for some algorithm.

Tcl has no direct support for closures, but they can emulated using eval mechanisms, in particular, commands uplevel and upvar. For examples, see block-local variables, Custom curry, Serial summing.


First example. The following command accept a block of code and executes it in specified file catalog.

 proc temp-chdir {dir block} {
         set cd [pwd]
         cd $dir
         uplevel $block
         cd $cd
 }

 # sample usage:
 temp-chdir / {puts "I'm in [pwd]"}

With upvar and uplevel it is simple to write custom iterators over some structure, like this:

 proc foreach-pocket {pw block} {
         upvar 1 $pw pwvar
         foreach p [get-container-pockets] {
                 set pwvar $p
                 uplevel 1 $block
         }
 }

 # sample usage
 foreach-pocket p {
  puts "Processing $p"
 }

mfi


Another example of such style of code can be found on How do I read and write files in Tcl page.


Arjen Markus - Could closures not be simulated very elegantly using the [interp alias] command? As this allows you to associate additional arguments to a command, it seems to me that one can capture local state that way. Just a thought, as I have not worked out the details yet, certainly not in relation to the above examples.

Donal Fellows - Note that the [namespace code] command creates something very much like closures, the main differences being that the variables and commands in the "closure" are accessible through other means and the "closure" must be explicitly deleted. (Perl also has a way of giving the effect of closures with my variables.)

mfi - See also: Closures. May be merge the pages somehow?