No, not quite. Namespaces and call frames are very different concepts. A namespace is a hierarchical structure of names that can disambiguate synonyms. You might have three variables named foo
in your program, but they won't clash if you put them in different namespaces. Namespaces can be used both for variable and command names. Once created with namespace eval
a namespace's contents are always accessible until you call namespace delete
on it.
A call stack is a sequence of stack frames. The first stack frame, #0, always exists. Other stack frames are created whenever a command is called (this goes mostly for commands that are user-defined procedures, the "built-in" commands follow their own rules). They are destroyed again when the command returns. So if you call command A, and A calls command B, and B calls command C, you have a call stack that looks like this:
#3 : <C's variables>
#2 : <B's variables>
#1 : <A's variables>
#0 : <global and namespace variables>
Each stack frame is a scope in the sense that only the variables that are created there or imported into it can be accessed, unless you use upvar
. Everything else is hidden. In most programming languages, names from an outside scope, such as the global scope, can be automatically accessed from an inner scope. Not so in Tcl.
Using upvar
you can let a command look at things outside its own stack frame. C could, for instance, use upvar #0 foo bar
to create an alias (bar
) for the global variable foo
, or use upvar 1 baz qux
(note without a #) to create an alias (qux
) for the variable baz
in B's stack frame.
The uplevel
command can be used along the same lines to execute a script in another stack frame, including the global one. During the execution, the script can access everything that is in that stack frame, but nothing else, including the variables in the stack frame that uplevel
was called from.
C can also create an alias for the namespace variable ::abc::def
using upvar #0 ::abc::def ghi
, but don't do that, use namespace upvar ::abc def ghi
instead.
Instead of upvar #0 foo foo
you can use global foo
to import a global variable. Inside a command defined in a namespace, the variable
command can import variables defined in the same namespace.
It is often useful to upvar
or uplevel
into #0 (the global frame) or 1 (the caller's frame). Using other frame numbers is error-prone and usually an indication of poor design. The invocation upvar 0 foo bar
creates an alias (bar
) for a variable (foo
) in the same stack frame, which can be surprisingly useful.
Commands that are called by events being processed execute outside the call stack, using the global level. There is no way for them to reach inside the active stack frames and access variables that reside there.
A simple demonstration:
namespace eval ::abc {
variable def 42
proc xyz {} {
variable def
}
}
set foo 1138
proc A {} {
B
}
proc B {} {
set baz 1337
C
}
proc C {} {
upvar #0 foo bar
puts $bar
upvar 1 baz qux
puts $qux
namespace upvar ::abc def ghi
puts $ghi
}