tcl Variables Scoping


Example

set alpha 1

proc myproc {} {
    puts $alpha
}

myproc

This code doesn't work because the two alphas are in different scopes.

The command set alpha 1 creates a variable in the global scope (which makes it a global variable).

The command puts $alpha is executed in a scope that is created when the command myproc executes.

The two scopes are distinct. This means that when puts $alpha tries to look up the name alpha, it doesn't find any such variable.

We can fix that, however:

proc myproc {} {
    global alpha beta
    puts $alpha
}

In this case two global variables, alpha and beta, are linked to alias variables (with the same name) in the procedure's scope. Reading from the alias variables retrieves the value in the global variables, and writing to them changes the values in the globals.

More generally, the upvar command creates aliases to variables from any of the previous scopes. It can be used with the global scope (#0):

proc myproc {} {
    upvar #0 alpha alpha beta b
    puts $alpha
}

The aliases can be given the same name as the variable that is linked to(alpha) or another name (beta / b).

If we call myproc from the global scope, this variant also works:

proc myproc {} {
    upvar 1 alpha alpha beta b
    puts $alpha
}

The scope number 1 means "the previous scope" or "the caller's scope".

Unless you really know what you're doing, #0, 0, and 1 are the only scopes that make sense to use with upvar. (upvar 0 creates a local alias for a local variable, not strictly a scoping operation.)

Some other languages define scope by curly braces, and let code running in each scope see all names in surrounding scopes. In Tcl one single scope is created when a procedure is called, and only its own names are visible. If a procedure calls another procedure, its scope is stacked on top of the previous scope, and so on. This means that in contrast with C-style languages that only have global scope and local scope (with subscopes), each scope acts as an enclosing (though not immediately visible) scope to any scope it has opened. When a procedure returns, its scope is destroyed.

Documentation: global, upvar