set - Read and write variables http://www.purl.org/tcl/home/man/tcl8.5/TclCmd/set.htm '''set''' ''varName ?value?'' Returns the value of variable ''varName''. If ''value'' is specified, then set the value of ''varName'' to ''value'', creating a new variable if one doesn't already exist, and return its value. If ''varName'' contains an open parenthesis and ends with a close parenthesis, then it refers to an array element: the characters before the first open parenthesis are the name of the array, and the characters between the parentheses are the index within the array. Otherwise ''varName'' refers to a scalar variable. Normally, ''varName'' is unqualified (does not include the names of any containing [namespace]s), and the variable of that name in the current namespace is read or written. If ''varName'' includes namespace qualifiers (in the array name if it refers to an array element), the variable in the specified namespace is read or written. If no procedure is active, then ''varName'' refers to a namespace variable (global variable if the current namespace is the global namespace). If a procedure is active, then ''varName'' refers to a parameter or local variable of the procedure unless the '''[global]''' command was invoked to declare ''varName'' to be global, or unless a '''[variable]''' command was invoked to declare ''varName'' to be a namespace variable. [rdt] Or unless [upvar] provides an alias to "varName". ---- [[ A web page which references the various valid forms that '''value''' can take, such as 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 readable See also "An essay on Tcl dereferencing" [http://www.phaseit.net/claird/comp.lang.tcl/tcl_deref.html] ---- 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 res as last command in a proc instead of return $res Before ''[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 } ;#RS Might 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 5 However, 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 5 or, in fact, you could use just command substitution (which is performed once for each [[ ] pair): % puts [set [set var]] ;# as does this 5 Similarly, 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 = 13 The 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 set is a valid command, and that set x set set y a set z b $x $y $z is 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} {} 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 break However, something about it has always bothered me: I just dislike programming to the side-effects. I've submitted a TIP [http://tip.tcl.tk/58] [[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 [eval]ing or [expand]ing. 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 $ls A more concrete example: % set ls [sets a b {1 2 3 4 5}] 3 4 5 % puts $ls 3 4 5 % puts $b 2 As 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 2 [Duoas] 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 1000 If 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 ---- See also: * [?set] * [expr] * [trace] * [unset] * [take] ---- !!!!!! [Tcl syntax help] - [Arts and Crafts of Tcl-Tk Programming] - %|[Category Command]|% !!!!!! ---- '''[LVwikignoming] - 2010-07-01 13:03:52''' A 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.