'''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 ======none 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! ====== ** Array Variables ** 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%|%ycl proc step]`, which monitors every command and variable substitution in a script. ** Asymmetry with `[set%|%set]` ** 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 ====== ** See also ** [set]: [variable]: [double substitution] and [Dereferencing]: [how do i do $$var - double dereferencing a variable]: [Variable substitution in -command scripts]: [Quoting Hell]: <> Tutorial