Variable substitution, one of the substitutions defined in the dodekalogue, is one of the mechanisms for retrieving the value of variables in Tcl.
set v aValue puts $v
The $v notation tells Tcl to retrieve the value of the variable v, whose value is
aValue
The $ notation was added to Tcl for coding convenience and is short for
set v
The following lines are equivalent:
puts $v puts [set v]
When dynamically composing a variable name, set can be used where $ can't. In the following example, Tcl substitutes the value of i and then set returns the value of var1, var2, var3.
foreach i {1 2 3} {puts [set var$i]}
The following code fails because Tcl tries to substitute $var and then $i, but finds that var is not defined.
#warning: example of bad code foreach i {1 2 3} {puts $var$i} ;# this fails because $var is undefined
Another approach that is not recommended:
foreach i {1 2 3} {eval puts \$var$i}
Using set in place of the $ variable can help to illuminate the behaviour of Tcl. The following line pairs are equivalent:
foreach i {1 2 3} {puts $var$i} ;# this fails because $var is undefined foreach i {1 2 3} {puts [set var][set i]} ;# this fails because $var is undefined foreach i {1 2 3} {puts [set var$i]} foreach i {1 2 3} {puts [set var[set i]]}
When accessing an array variable, the member name is computed and then looked up in the array, so arrays are a good fit when programming in a style that leads to composition of variable names:
foreach i {1 2 3} {set var($i) value$i} foreach i {1 2 3} {puts $var($i)}
The last line is equivalent to:
foreach i {1 2 3} {puts [set var([set i])]}
Although there are often better alternatives to variable indirection, it can be implemented in the following ways:
set a something set pointer a puts [set $pointer] ;#good style puts [set [set pointer]] ;#more verbose style eval puts \$$pointer ;#oh blimey, it's "eval"! Run away!
Variable substitution is not symmetrical with set in its syntax. This is because set has the luxry of knowing where the word ends, while variable substitution, which may be interpolated into another string, does not.
set var(one)two) three #doesn't work, because Tcl sees $var(one) puts $var(one)two)
Using braces solves the problem in this particular case:
puts ${var(one)two)}
Of course, it's always possible to use set:
puts [set var(one)two)]
PYK 2016-09-25: The general alternative to $ syntax for array variables is a bit tricky. array get can't be used because it interprets is arguments as patterns. In order to get the quoting right but still provide for substitution in the index portion of the variable name, a little help from subst is needed. For example, here is an implementation of a procedure that takes the name and index of a variable and generates a script that retrieves the corresponding value in the array:
proc varsubst {name index} { return "::set [list $name](\[::subst [list $index]])" }
This type of syntax manipulation is used, for example, in ycl proc step, which monitors every command and variable substitution in a script.
Some variables are simply not accessible via variable substituion syntax.
One simple example:
set var\}1 val
The only way to access var} is set:
set var\}1