[Richard Suchenwirth] 2002-11-14 - A ''reference'' is something that refers, or points, to another something (if you pardon the scientific expression). In C, references are done with *pointers* (memory addresses); in Tcl, references are strings ([everything is a string]), namely names of variables, which via a hash table can be resolved (dereferenced) to the "other something" they point to: puts foo ;# just the string foo puts $foo ;# dereference variable with name of foo puts [set foo] ;# the same This can be done more than one time with nested [set] commands. Compare the following C and Tcl programs, that do the same (trivial) job, and exhibit remarkable similarity: #include int main(void) { int i = 42; int * ip = &i; int ** ipp = &ip; int ***ippp = &ipp; printf("hello, %d\n", ***ippp); return 0; } ...and Tcl: set i 42 set ip i set ipp ip set ippp ipp puts "hello, [set [set [set [set ippp]]]]" The C asterisks correlate to [set] calls in derefencing, while in Tcl similar markup is not needed in declaring. But why four [set]s for three asterisks? Because also the first mention of ''i'' in c is a dereference, to pass its value into ''printf''; Tcl makes all four of them explicit (otherwise, you'd see ''hello, i''). One dereference is so frequent that it is typically abbreviated with ''$varname'', e.g. puts "hello, [set [set [set $ippp]]]" has [set] where C uses asterisks, and $ for the last (default) dereference. The hashtable for variable names is either global, for code evaluated in that scope, or local to a [proc]. You can still "import" references to variables in scopes that are "higher" in the call stack, with the [upvar] and [global] commands. (The latter being automatic in C, given the names are unique; else, the innermost scope wins). (This little piece was written to defuse the superstition that Tcl has no references, or needs more of the same. See also [Pass by reference], which is also called "call by name", pretty exactly describes how Tcl implements it...) ---- One visitor to the [Tcl chatroom] wondered why expr $$item turns the value of a variable whose name is in ''item'' from 530E001 to 5300.0 - what happens is that the Tcl parser does a first derefencing, e.g., if ''item'' has the value ''ID'': * expr $ID and [expr] does a second dereferencing (or substitution). Not much arithmetics to do on its input (which, interpreted as a number, looks like scientific notation), but at least you get it back in canonical ''double'' representation... ---- See also "An Essay on Tcl Dereferencing" [http://www.phaseit.net/claird/comp.lang.tcl/tcl_deref.html] and "[how do i do $$var - double dereferencing a variable]". ---- [TV] Dereferencing could maybe be phrased as a form of variable substitution, unless I miss some major point of the page.. Interestingly, the ideas of functional (de-) composition probably can be thought to apply practically, which in tcl normally means that the evaluation levels of a nested level command are followed in the variable substitution. ---- [MG] offers this largely-working method of dereferencing on Feb 2nd 2006. It allows you to do, for instance... set a "some real value" set b ::a proc foo {} { global a b; puts "Value: $$b" } And get 'some real value' as the result of [[foo]]. (It works by overloading [proc], and thus anything run outside of a proc won't have the dereferencing.) It's flaw is that it assumes (completely incorrectly) that only characters in the regexp range [[:alnum:]_] are valid for variable substituation after a '''$''' - this is (I think) normally correct, but you can, of course, use things like ${some [long] name} $some\ long \ name But all it needs is a regexp pattern which does properly match all the valid ways to access a var through '''$''', and it should work like a charm - if anyone knows a more accurate value, please alter the code. It will also work on an infinite number of $'s. rename proc overload_proc overload_proc proc {name args body} { while {[regexp {\$(\$+[[:alnum:]_]+)} $body]} { regsub -all {(\$(\$+[[:alnum:]_]+))} $body "\[set \\2\]" body } ::overload_proc $name $args $body } # and a small test proc foobar {} { set real "yay!" set p1 real set p2 p1 set p3 p2 puts "$real / $$p1 / $$$p2 / $$$$p3" } foobar;# prints "yay! / yay! / yay! / yay! (Yup, it basically just edits $$$foo out to [set [set $foo]] which is the "real" way to do nested variables/dereferencing. Check [[info body foobar]] after running the code+demo above, if you want to see the result.) (Oh, that does also mean that if you have, for instance, set myvar {some text we $$foo don't want evaled or edited} you'll end up with set myvar {some text we [set $foo] don't want evaled or edited} which is wrong. But this is just a 2am piece of example code ;) ---- [Category Concept] | [Arts and crafts of Tcl-Tk programming]