Variable Aliases with upvar
The upvar command is useful in any situation where you have the name of a variable stored in another variable. In Example 7-2 on page 82, the loop variable param holds the names of other variables. Their value is obtained with this construct:
puts stdout "\t$param = [set $param]"
Another way to do this is to use upvar. It eliminates the need to use awkward constructs like [set $param]. If the variable is in the same scope, use zero as the scope number with upvar. The following is equivalent:
upvar 0 $param x
puts stdout "\t$param = $x"
Associating State with Data
Suppose you have a program that maintains state about a set of objects like files, URLs, or people. You can use the name of these objects as the name of a variable that keeps state about the object. The upvar command makes this more convenient:
upvar #0 $name state
Using the name directly like this is somewhat risky. If there were an object named x, then this trick might conflict with an unrelated variable named x elsewhere in your program. You can modify the name to make this trick more robust:
upvar #0 state$name state
Your code can pass name around as a handle on an object, then use upvar to get access to the data associated with the object. Your code is just written to use the state variable, which is an alias to the state variable for the current object. This technique is illustrated in Example 17-7 on page 232.
Namespaces and upvar
You can use upvar to create aliases for namespace variables, too. Namespaces are described in Chapter 14. For example, as an alternative to reserving all global variables beginning with state, you can use a namespace to hide these variables:
upvar #0 state::$name state
Now state is an alias to the namespace variable. This upvar trick works from inside any namespace.
Commands That Take Variable Names
Several Tcl commands involve variable names. For example, the Tk widgets can be associated with a global Tcl variable. The vwait and tkwait commands also take variable names as arguments.
Upvar aliases do not work with text variables.
The aliases created with upvar do not work with these commands, nor do they work if you use trace, which is described on page 183. Instead, you must use the actual name of the global variable. To continue the above example where state is an alias, you cannot:
button .b -textvariable state(foo)
Instead, you must
button .b -textvariable state$name\(foo)
The backslash turns off the array reference so Tcl does not try to access name as an array. You do not need to worry about special characters in $name, except parentheses. Once the name has been passed into the Tk widget it will be used directly as a variable name.