
- set varName ?value?
[ A web page which references the various valid forms that value can take, such as
as we get. ]
The reading form set x (without value) works the same as $x, so you could write Tcl scripts without a single dollar sign. Its advantage is that it can be nested, so cascaded dereferencing is possible:
When a proc is left without a return, it returns the last evaluated result. It is therefore an idiom (which however is less popular these days) to write
As Tcl has no reserved words, you can even write your own set command (make sure its effects are like the original, otherwise most Tcl code might break). For instance, this version says what it does, on stdout:
How can I do a double indirect? - Why doesn't $$var work?There is one and only one level of substitution possible with every pass through the interpreter. Also, when doing variable substitution, the interpreter finds the dollar sign and then takes everything following it up until the next invalid character (where invalid is defined as anything other than a letter, digit, or underscore) as the name of the variable - well, that is, unless it finds array notation or the ${varname} form.In the case of $$var, the character after the first dollar sign is an invalid character (another dollar sign), so there is no variable name and variable substitution is not performed (the dollar sign is left as is) and scanning starts again for any dollar signs and a following variable name. It is immediately found at that second dollar sign, the substitution is performed, and scanning for dollar signs resumes with whatever was after the variable name. Since there isn't anything else, substition is done for this pass through the interpreter (remember it's only done once).The eval command runs its arguments through the interpreter, so you could use eval to cause a second pass through the interpreter, and thus, have $$var work:
Clif Flynt: When I'm teaching a class, I point out that
MSW For those who dislike doing multiple assignments at once with foreach in the style
Duoas The foreach..break idiom is so prevalent in Tcl, and so common, that experienced Tcler's automatically recognize it as a set replacement idiom:
MJ - in 8.5 we have lassign which is sets with the arguments reversed. The example above then translates to:
Draft of text which might be easier to read for beginners to read.The keyword set stamps a pattern onto a token.Programs are machines which do not work with the grinding of physical gears, but rather they create and change information. Because of this, it's important to have something with which to pass around information between various parts of the machine. Most computer people call these tokens "variables." However, I prefer to use a typical English noun, instead of a word which is ordinarily an adjective ;-). In TCL, set is the tool you use to stamp these tokens with a pattern.example:
LVwikignoming - 2010-07-01 13:03:52A recent email on the TCLCORE mailing list discussed a problem. The user was attempting to add a new minor command to the standard array command. However, the code was generating peculiar results. The solution, as provided by dkf was to change the proposed code so that the proc was using ::set instead of just plain set. The reason was that the ::tcl::array namespace already had a set command in that namespace that was overriding and resulting in the unexpected behavior.So, this note is not specific to set, but applies in general. If you are seeing behavior that reports a problem that is unexpected, examine the code closely to see if you need to add namespacing to the commands in use.
set a unquotedstring
set b "substitution processed string"
set c {quoted literal string}
set d [results of a command]as well as a discussion of Tcl string escapes such as the ever popular \n , \t , and those oh so hard to figure out \uHEXSTRING as well as other things, can be found at Dodekalogue, which is as close to the http://www.tcl.tk/man/tcl8.5/TclCmd/Tcl.htm
as we get. ]The reading form set x (without value) works the same as $x, so you could write Tcl scripts without a single dollar sign. Its advantage is that it can be nested, so cascaded dereferencing is possible:
set foo 1 set bar foo puts [set $bar] ;# retrieves indirectly the value of foo puts [set [set bar]] ;# equivalent, but less readableSee also "An essay on Tcl dereferencing" [1]
When a proc is left without a return, it returns the last evaluated result. It is therefore an idiom (which however is less popular these days) to write
set resas last command in a proc instead of
return $resBefore return got byte-compiled (i.e., before Tcl 8.4), such a set used to be the fastest way to use the value of a variable as the return value from a proc. The danger is that someone might add code after the set statement, so the expected result would be lost...
As Tcl has no reserved words, you can even write your own set command (make sure its effects are like the original, otherwise most Tcl code might break). For instance, this version says what it does, on stdout:
rename set _set
proc set {var args} {
puts [list set $var $args]
uplevel 1 _set $var $args
} ;#RSMight help in finding what was going on before a crash. When sourced in a wish app, shows what's up on the Tcl side of Tk (as long as you can find the program's stdout). Pretty educative!How can I do a double indirect? - Why doesn't $$var work?There is one and only one level of substitution possible with every pass through the interpreter. Also, when doing variable substitution, the interpreter finds the dollar sign and then takes everything following it up until the next invalid character (where invalid is defined as anything other than a letter, digit, or underscore) as the name of the variable - well, that is, unless it finds array notation or the ${varname} form.In the case of $$var, the character after the first dollar sign is an invalid character (another dollar sign), so there is no variable name and variable substitution is not performed (the dollar sign is left as is) and scanning starts again for any dollar signs and a following variable name. It is immediately found at that second dollar sign, the substitution is performed, and scanning for dollar signs resumes with whatever was after the variable name. Since there isn't anything else, substition is done for this pass through the interpreter (remember it's only done once).The eval command runs its arguments through the interpreter, so you could use eval to cause a second pass through the interpreter, and thus, have $$var work:
% set a 5
5
% set var a
a
% puts $$var ;# This doesn't work
$a
% eval puts $$var ;# This does - but it's dangerous
5However, if the contents of var contain any special characters (e.g. whitespace, semicolon) you'll run into problems.A better method is to take advantage of the behaviour of the set command when given only one argument, and combine command substitution with variable substitution: % puts [set $var] ;# This works safely
5or, in fact, you could use just command substitution (which is performed once for each [ ] pair): % puts [set [set var]] ;# as does this
5Similarly, to print the values of var1, var2, and var3: set var1 3.14159
set var2 hello
set var3 13
foreach num {1 2 3} {
puts "var$num = [set var$num]"
}will output:
var1 = 3.14159
var2 = hello
var3 = 13The upvar command can also be used to derefence variables.In addition, the interpreter includes the command subst which can be used to perform substitutions.Note that all of the above applies to array variables also.Clif Flynt: When I'm teaching a class, I point out that
set set setis a valid command, and that
set x set
set y a
set z b
$x $y $zis a valid Tcl command to assign the value b to variable a. Looking at this makes the students stop and think. And stare at me like I'm crazy.MSW For those who dislike doing multiple assignments at once with foreach in the style
foreach {a b c} {1 2 3} {}and who don't want to use lassign, here is a multiple argument set (with help from RS): if {[info procs tcl::set]=={}} then {rename set tcl::set}
proc set {args} {
switch [llength $args] {
0 { return -code error {wrong # args: should be set varname ?newvalue? ?varname ?newvalue?? ...}}
1 { return [uplevel "tcl::set [lindex $args 0]"] }
2 { return [uplevel "tcl::set [lindex $args 0] [lindex $args 1]"] }
default {
uplevel "tcl::set [lindex $args 0] [lindex $args 1]"
return [uplevel "set [lrange $args 2 end]"]
}
}
}Use like this% set a 1 b 2 c 3 => 3 % set d 15 e [expr int(100*rand())] c => 3 % list $a $b $c $d => 1 2 3 15
Duoas The foreach..break idiom is so prevalent in Tcl, and so common, that experienced Tcler's automatically recognize it as a set replacement idiom:
set ls [list 1 2 3]
foreach {var1 var2 ...} $ls breakHowever, something about it has always bothered me: I just dislike programming to the side-effects. I've submitted a TIP [2] [is that the right TIP?] to extend the set command such that it can assign to multiple variables, but not as above, where the values to assign are interleaved with the variable names. Usually the values come from a list and the above implementation would require zipping variable names and values together before use, then evaling or expanding. It doesn't obviate the need to use that silly foreach..break idiom.Littered throughout my own code is the use of this simple little routine: proc sets args {
set names [lrange $args 0 end-1]
set values [lindex $args end]
uplevel 1 [list foreach $names $values break]
return [lrange $values [llength $names] end]
}And an example of use:sets x0 y0 x1 y1 [.canvas coords my-rectangle-tag]This is much more Tclish and intuitive. Note also that you can get what is not used for later use (foreach requires you use it now or not at all):
set ls [sets a b $ls] # do something with $a and $b, and maybe sometime later with the rest of $lsA more concrete example:
% set ls [sets a b {1 2 3 4 5}]
3 4 5
% puts $ls
3 4 5
% puts $b
2As per my TIP submission, the set command is easily extended to have such functionality without slowing it down when used as per the current specification (well, except one or two processor instructions when errors occur). When used in the extended form it is faster than using foreach, which has a lot of extra stuff to handle multiple, concurrent lists.MJ - in 8.5 we have lassign which is sets with the arguments reversed. The example above then translates to:
% set ls [lassign {1 2 3 4 5} a b]
3 4 5
% puts $ls
3 4 5
% puts $b
2Duoas Me feels stupid for having missed that... I learned Tcl moving into 8.0 and I'm still a little behind in a lot of 8.5 improvements.MJ - No need to feel stupid, Tcl 8.5 has a lot of new goodies, see Changes in Tcl/Tk 8.5.Draft of text which might be easier to read for beginners to read.The keyword set stamps a pattern onto a token.Programs are machines which do not work with the grinding of physical gears, but rather they create and change information. Because of this, it's important to have something with which to pass around information between various parts of the machine. Most computer people call these tokens "variables." However, I prefer to use a typical English noun, instead of a word which is ordinarily an adjective ;-). In TCL, set is the tool you use to stamp these tokens with a pattern.example:
set variable "bananas were peeled" set a "oranges" set fruit "pears" set money 1000If you'd like, you can use braces there, instead of quotation marks... or, if you only have one word, you don't have to use any marks at all.
set mountain kilimanjaro
set phrase {What shall we do today?}There is a difference between using braces and using quotation marks in longer bits of text. Quotations allow you to use tokens within the text itself, or even embed tcl instructions.like this:set phrase "I want to journey to $mountain" set phrase "Last year I went to Africa [expr 1+1] times"Not only can you stamp a pattern onto a token with set - you can also get out the magnifying glass and read that token, using set. Some people will recognize this method from times when they have used msdos.look here:
set fruit
LVwikignoming - 2010-07-01 13:03:52A recent email on the TCLCORE mailing list discussed a problem. The user was attempting to add a new minor command to the standard array command. However, the code was generating peculiar results. The solution, as provided by dkf was to change the proposed code so that the proc was using ::set instead of just plain set. The reason was that the ::tcl::array namespace already had a set command in that namespace that was overriding and resulting in the unexpected behavior.So, this note is not specific to set, but applies in general. If you are seeing behavior that reports a problem that is unexpected, examine the code closely to see if you need to add namespacing to the commands in use.
