[Richard Suchenwirth] 2005-12-15 - A colleague wanted some sugar for [upvar] variables to [pass by reference], but as the use of ''xproc'' prevented the names of such procedures to end up in [tclIndex], we cooked up (it was lunch) this minimally invasive version: ====== proc use_refs {{char &}} { foreach v [uplevel 1 {info locals}] { if [string match $char* $v] { uplevel 1 "upvar 1 \${$v} [string range $v 1 end]" } } } ====== I insert here a somewhat different (and not equivalent) approach: ====== proc refs {args} { foreach var $args { # use an K-combinator (in form of [lindex [list $x $y] 0]) to # pass the parameter name to upvar and unset it in time before # upvar creates an equally-named link. set lvar [list $var];# to shorten the following line a little uplevel 1 "upvar 1 \[lindex \[list \[set $lvar\] \[unset $lvar\]\] 0\] $lvar" } } ====== This variant will accept a list of variablenames, which it assumes to be names of those parameters, that will be replaced by the linked variables they previously contained as values... sounds quite complicated, but isn't: proc myappend {var1 var2 elem} { refs var1 var2; append var1 $elem; lappend var2 $elem } The remainder of this page deals with the original approach, so if you like to comment on the "refs", then please do so above this line. That's all. This command is preferrably called first inside a proc, and [upvar]s all arguments that begin with a specific character, the default being "&" - it runs code like upvar 1 ${&foo} foo in the caller's scope. Testing: ====== proc test_refs {a &b} { use_refs puts a=$a,b=$b set b new_value } % set bar 42 42 % test_refs foo bar a=foo,b=42 So the values of ''a'' (by value) and ''b'' (by reference) are readable; and the side effect of changing ''b'' in the caller did also happen: % set bar new_value ====== ---- [MG] offers an alternative on the same day (Dec 15 '05) which differs slightly from the above - it probably won't be of much use, but it was quite interesting to write :) This code allows passing by reference in the actual call to the proc, rather than in the proc's definition, by overloading the [proc] command. For example: ====== % proc test_refs2 {baz} { set baz "$baz !" } % test_refs2 "hello" hello ! % set foo "bar" bar % test_refs2 $foo bar ! % set foo bar % test_refs2 &foo bar ! % set foo bar ! ====== And the code: ====== rename proc _proc _proc proc {name args body} { set prefix "" foreach x $args { set varname [lindex $x 0] set string { if { [string match "&*" $XNAME] } { upvar 1 [string range $XNAME 1 end] "XNAME[unset XNAME]" } } ;# set string ... set string [string map [list XNAME $x] $string] append prefix $string };# foreach uplevel 1 [list ::_proc $name $args $prefix$body] };# _proc ====== I'm not sure whether that [uplevel] at the end is necessary or not, but it's intended purpose is to make sure new procs come out in the namespace the [proc] command was called from. Whether it works or not is untested. ---- [Arts and crafts of Tcl-Tk programming] [Category Discussion]