Version 5 of invoke

Updated 2007-05-09 13:03:36 by NEM

NEM 9 May 2007: Here is a little proc that I use quite regularly. It is useful for avoiding Quoting Hell in the common case of invoking a callback command with some additional arguments. Typically we expect the callback to consist of one or more words given as a list (e.g. "string match"), which is the usual case for built-in commands (e.g. lsort -command, or after). Usually you'd invoke the command using uplevel, but you have to take care to make sure arguments are quoted correctly while still expanding the command, ending up with some code like:

 uplevel #0 $callback [list $arg1] [list $arg2] ..

This works well, but is a bit hard to read if you are not familiar with the idiom. This is where invoke comes in: it handily packages up this familiar idiom into a single command:

 proc invoke {level cmd args} {
     if {[string is integer -strict $level]} { incr level }
     uplevel $level $cmd $args
 }
 invoke $callback $arg1 $arg2 ...

To be a bit more efficient, we can ensure uplevel is passed a single list, which avoids any possibility of string concatenation (Tcl_UplevelObjCmd does its best to avoid this, but cannot always do so):

 proc invoke {level cmd args} {
     if {[string is integer -strict $level]} { incr level }
     # Note 8.5ism
     uplevel $level [linsert $cmd end {*}$args]
 }

I'm not sure if this really makes a noticeable impact on performance in typical cases, though. (If $cmd doesn't have a string rep, then uplevel does this automatically, from my reading of the source code).


[ Category Example ]