KPV After having read a criticism of tcl that it doesn't have true pass by reference--you have to fake it with using upvar -- I thought I'd write a tcl-only clone of proc called xproc that will automatically give you pass by reference ala C++ syntax. Specifically, you say proc myproc {arg1 &arg2 arg3 &arg4} {body} and arg2 and arg4 will automatically be pass by reference.
proc xproc {pname arglist body} { set newarglist {} set ups "" foreach arg $arglist { if {[string match "&*" $arg]} { set arg [string range $arg 1 end] append ups "upvar 1 \$_$arg $arg;" lappend newarglist _$arg } else { lappend newarglist $arg } } proc $pname $newarglist [concat $ups $body] }
Here's a sample usage:
xproc myproc {&arr} { foreach n [array names arr] { puts "arr($n) => $arr($n)" } } array set myarray {1 one 2 two 3 three} myproc myarray
RS: Nice! I'd like to speak in defense of upvar, which is no black magic, but just a scoping mechanism. Like everything, references in Tcl are strings, implemented as variable names, which are valid in their scope. Now as proc variables normally have local scope (which is a good thing!), you have to dereference variables from other (only upper) scopes if required, and that is precisely what upvar does. And: even seeming innocent statements like
set i 0
already contain a reference - to the variable "i". In general, every time you mention a variable name without prefixing it with $, you're working with a reference. (See Dangers of creative writing for a list of commands that use references, and possibly create new variables).
But a style question: Aren't the last three lines in xproc above equivalent to
proc $pname $newarglist [concat $ups $body]
? This may seem terser, but it saves two variables and two commands (one of which is an eval) - and my experience is: the less I write, the better (for debugging at least ;-) -- KPV You're correct, I changed it. Despite years of tcl programming I still don't think of proc as a command--last vestiges of my C background?