William Wragg 21-nov-2002 - While playing with [Lua] I discovered the joys of first class functions. This combined with the use of associative arrays was so much fun to program with that I started wanting them in other languages I use. I found a similar idea in [Arrays as cached functions] but this wasn't quite what I wanted. What I wanted were for procs to be stored in arrays, and then called by just getting the value of the array. (Also see [Arrays of function pointers] - [KPV]) This is what I came up with: # unique integer ID generator, at first call gives 1, then 2, 3, ... proc intgen {{seed 0}} { set self [lindex [info level 0] 0] proc $self "{seed [incr seed]}" [info body $self] set seed } # Lambda proc with caller scope life dependenecy. # When the caller scope dies so does the lambda proc. proc sproc {args body} { set name sproc[intgen] uplevel 1 set __$name - uplevel 1 "trace variable __$name u {rename $name {} ;#}" proc $name $args $body return $name } # Use this proc to run the sprocs stored in arrays. # The value from the array - sproc - is eval'ed to produce # the proc and name. This proc name and the args list is # then eval'ed again to produce the output. proc call {sproc args} { eval [eval $sproc] $args } The '''sproc''' procedure is just a lambda procedure from [Lambda in Tcl]. To use the above do something like - note the use of the global namespace for accessing the array value: set s(spfac) { sproc x { expr {$x<2? 1: $x * [call $::s(spfac) [incr x -1]]} } } Which is the same as: proc pfac x { expr {$x<2? 1: $x * [pfac [incr x -1]]} } You use the '''sproc''' like: call $s(spfac) 30 1409286144 Another simple example would be: set arr(hello) { sproc var { puts $var } } call $arr(hello) "hello world" hello world The overall affect is almost what I wanted. The way of calling the '''sproc'''s is a bit gludgy, but all other ways I could think of used traces, which I didn't want. I wanted everything to be in the array and a few handler procs. Creating and destroying procs is not the fastest process in the world: puts pfac:[time {pfac 30} 1] pfac:81 microseconds per iteration puts spfac:[time {call $s(spfac) 30} 1] spfac:2749 microseconds per iteration But hell it was fun figuring it all out. These could even be combined with [Persistent arrays] and [Tequila] for something interesting. ---- [KPV] My biggest problem with ideas like this and also things like [Arrays of function pointers] and even object inheritance is that it can make it very hard for someone new to a code base to read code and understand what's going on. Trying to determine which actual procedure gets call at a given line of code can be almost impossible to determine without actually stepping the code in a debugger. Also, how do you debug a procedure stored in an array? ---- [RS]: If I read your code right, ''call'' creates a new lambda every time, with constant body. I think it's much easier to do it like this: set s(spfac) [sproc x {...}] ;# define only once $s(spfac) 30 ;# call by dereferencing the array element ..and for easier reading I would still use ''lambda'' for ''sproc'', 'cause that's what's it called in the literature too...