Upvar creates a link to a variable in a different stack frame, sometimes called a call stack, or a different scope.
Upvar is also used to create an alias for a global (or namespace) variable 2. But a namespace is created only by the namespace eval command. A new stack frame is created by the proc command.
Namespace and call stacks appear to be two ways that the TCL naming context can change. Upvar and Uplevel can work on both namespaces and call stacks.
Did I get it right? I have yet to see a direct comparison between call stacks and namespaces, hence my question.
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
fooin 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 withnamespace evala namespace's contents are always accessible until you callnamespace deleteon 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:
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
upvaryou can let a command look at things outside its own stack frame. C could, for instance, useupvar #0 foo barto create an alias (bar) for the global variablefoo, or useupvar 1 baz qux(note without a #) to create an alias (qux) for the variablebazin B's stack frame.The
uplevelcommand 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 thatuplevelwas called from.C can also create an alias for the namespace variable
::abc::defusingupvar #0 ::abc::def ghi, but don't do that, usenamespace upvar ::abc def ghiinstead.Instead of
upvar #0 foo fooyou can useglobal footo import a global variable. Inside a command defined in a namespace, thevariablecommand can import variables defined in the same namespace.It is often useful to
upvaroruplevelinto #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 invocationupvar 0 foo barcreates 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: