Version 9 of Implicit upvar

Updated 2006-04-28 11:35:54

Richard Suchenwirth 2002-11-07 - Tcl's upvar command ties a local variable in a proc to another in a higher scope in the call stack - typically the caller's (upvar 1). This way, references (like pointers in C, or literally "call by name") can be implemented. The Tcl Style Guide recommends "Name" as suffix for upvar-ed arguments, e.g.

 proc example {varName value} {
    upvar 1 $varName var
    ...}

which is a good convention for readable code. However, after a hard day of adjusting *const** references in C++, frustration with that baroque language brought me to think of other ways in the freeest language I know - Tcl. I did not want to repeat the *const** experience, but simple references can be sugared by overloading the proc command.

For this breakfast fun project, I chose the slightly different name pruc ("procedure with upvar components"). It is called just like proc, with the added behavior that arguments declared with prefix * or & are implicitly upvar-ed to a local variable without that prefix, before the original proc body. Simple enough, but again a few lines of code have changed the face of our language considerably: }

 proc pruc {name argl body} {
    set prefix ""
    foreach {upvar var} [regexp -all -inline {[*&]([^ ]+)} $argl] {
        append prefix "\nupvar 1 \${$upvar} $var;"
    }
    proc $name $argl $prefix$body
 }

#------------- Testing:

 pruc demo {*i j} {
    set i $j
 }
 puts "[demo foo 42]/$foo"
 pruc demo2 {j &i} {
    set i $j
 }
 puts "[demo2 43 bar]/$bar"
 puts "generated body: [info body demo2]"

if 0 {...which shows on stdout:

 42/42
 43/43
 generated body: 
 upvar 1 ${&i} i;
    set i $j

}

See Pass by reference for an earlier alternative, and use_refs


escargo 15 Dec 2005 - I wonder if you thought about a different policy: When an argument name ends in "Name" (e.g., varName), automatically insert upvar $varName var into the synthesized procedure. That would follow the Style Guide.

KPV wouldn't work for me because I often have parameters with names like imageName, fileName and widgetName.

AMG: I wasn't aware that this Name suffix style had been codified, so I made up my own convention: I usually suffix "name" argument names with "_var". For instance, if I wrote a proc that as a side effect would set some variable in the caller's frame to the name of an image, I'd call that parameter imagename_var. To me that name suggests that the caller should pass the name of the variable storing the image name.

2006-04-28 wdb -- why so "Perl"ish with these cryptic signs? I prefer it human readable:

 proc refProc {name varlist body} {
    set varlist1 {}
    set upvarBody ""
    foreach var $varlist {
        if {[llength $var] > 1
            &&
            [lindex $var 0] eq "referenced"} then {
            set varName [lindex $var end]
            lappend varlist1 _$varName
            append upvarBody "upvar \$_$varName $varName" \n
        } else {
            lappend varlist1 $var
        }
    }
    uplevel [list proc $name $varlist1 $upvarBody$body]
 }

Example:

 refProc test {{referenced a} b} {
    append a $b
 }
 % set a Apfel
 Apfel
 test -Baum
 Apfel-Baum
 % set a
 Apfel-Baum

The only disadvantage I see is that it is not possible to use the argument name "referenced" with a default value in the arguments list -- which I find acceptable.