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]"...which shows on stdout:
42/42
43/43
generated body:
upvar 1 ${&i} i;
set i $jSee Pass by reference for an earlier alternative, and use_refsescargo 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 a -Baum
Apfel-Baum
% set a
Apfel-Baum
% # source code:
% list proc test [info args test] [info body test]
proc test {_a b} {upvar $_a a
append a $b
}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 is easy to remind, and which I find acceptable.fredderic: I liked this idea, but I liked one of the others also. So I thought I'd combine them, and this is what I came up with:
proc proc2 {name args body} {
set prefix ""
set magic {if {[string match "&*" ${ANAME}]} {upvar 1 [string range ${ANAME} 1 end] {XNAME}} {set {XNAME} ${ANAME}}}
foreach arg $args {
set var [string range $arg 1 end]
switch -exact -- [string index $arg 0] {
"&" {append prefix "upvar 1 \${$arg} $var\n"}
"*" {append prefix [string map [list ANAME $arg XNAME $var] $magic]\n}
}
}
proc $name $args $prefix$body
}It's lightly tested... Basically, &args will be upvar'd right off, while *args will be upvar'd if the value passed through starts with the &.One potential problem with all these solutions that I've seen, including mine; I don't think any of these will handle a default value terribly well. But then, I'll be stuffed if I can think of a clean idea on what exactly to do with a default value, especially in the & case.wdb -- meanwhile, same galaxy, some days later -- I've not only overtaken the idea but moreover, I've made a procedure xproc which is intended to be the "Eierlegende Wollmilchsau" (egg-laying wool-milk pig) which uses some three-to-five ideas from above ... too long to be really "short-and-elegant", so I can't cite it here (the documentation contains just 6 sub-topics). But, it is in productive use!
NEM 2008-05-13: Inspired by discussions on Tcl-Core related to Cloverfield, here is a page on Checked Implicit Upvar that shows a version that errors early if the named variables do not exist in the caller's scope.

