**Variable scope - global and upvar** !!!!!! '''[Tcl Tutorial Lesson 12%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' | '''[Tcl Tutorial Lesson 14%|%Next lesson%|%]''' !!!!!! Tcl evaluates variables within a ''scope'' delineated by procs, namespaces (see [Tcl Tutorial Lesson 31%|%Building reusable libraries - packages and namespaces%|%]), and at the topmost level, the `global` scope. The scope in which a variable will be evaluated can be changed with the `global` and `upvar` commands. The `global` command will cause a variable in a local scope (inside a procedure) to refer to the global variable of that name. The `upvar` command is similar. It "ties" the name of a variable in the current scope to a variable in a different scope. This is commonly used to simulate pass-by-reference to procs. You might also encounter the `variable` command in others' Tcl code. It is part of the namespace system and is discussed in detail in the [Tcl Tutorial Lesson 31%|%chapter on namespaces%|%]. Normally, Tcl uses a type of "garbage collection" called reference counting in order to automatically clean up variables when they are not used anymore, such as when they go "out of scope" at the end of a procedure, so that you don't have to keep track of them yourself. It is also possible to explicitly unset them with the aptly named `unset` command. The syntax for `upvar` is: ====== upvar ?level? otherVar1 myVar1 ?otherVar2 myVar2? ... ?otherVarN myVarN? ====== The `upvar` command causes `myVar1` to become a reference to `otherVar1`, and `myVar2` to become a reference to `otherVar2`, etc. The `otherVar` variable is declared to be at `level` relative to the current procedure. By default `level` is 1, the next level up, though it is best to always set it explicitly. If a number is used for the `level`, then level references that many levels up the stack from the current level. If the `level` number is preceded by a `#` symbol, then it references that many levels down from the global scope. If `level` is `#0`, then the reference is to a variable at the global level. If you are using upvar with anything except #0 or 1, you are most likely asking for trouble, unless you really know what you're doing. You should avoid using global variables if possible. If you have a lot of globals, you should reconsider the design of your program. Note that since there is only one global space it is surprisingly easy to have name conflicts if you are importing other people's code and aren't careful. It is recommended that you start global variables with an identifiable prefix to help avoid unexpected conflicts. ---- ***Example*** The `global` command can be used for data you need to share: ====== global logFile set logFile [open "log.out" w] proc writeLog {data} { global logFile puts $logFile "LOG: $data" } ====== This is a simplistic way to provide logging information. The `upvar` command can be used to pass variables "by reference": ====== proc SetPositive {variable value } { upvar 1 $variable myvar if {$value < 0} { set myvar [expr {-$value}] } else { set myvar $value } return $myvar # Or more concisely: # set myvar [expr {abs($myvar)}] } SetPositive x 5 SetPositive y -5 puts "X : $x Y: $y\n" ====== resulting in: ======none X : 5 Y: 5 ====== !!!!!! '''[Tcl Tutorial Lesson 12%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' | '''[Tcl Tutorial Lesson 14%|%Next lesson%|%]''' !!!!!!