Version 24 of scope

Updated 2004-10-14 23:20:32 by CMCc

Scope is a context within which to resolve names, binding names to values.

Tcl is capable of both lexical and dynamic scoping. Tcl requires lexical scope for command resolution, and prefers (or defaults to) dynamic scope for variable resolution within [proc].

Tcl has partitioned static scopes - a different binding can exist in each static scope for variables and commands with the same name.

Tcl has many scopes:

namespace is an hierarchal scope for binding the names of commands and variables. [variable] references a variable name in some namespace scope relative to the scope in which it is invoked, and [proc] creates a command in the namespace scope within which it is invoked. For this reason, namespace scope can be considered a lexical scope. Additionally, namespace scope is partitioned into distinct bindings for variable and command names.

global scope is a distinguished namespace scope, equivalent to the namespace :: in some interpreter. global scope is also a distinguished call frame scope - equivalent to upvar #0. Global scope can be referenced by the [global] command.

hidden scope is a per-interpreter scope for interp hidden commands.

call frame scope is the context of some call frame in the current evaluation.

proc local scope is the context within which all otherwise unqualified variable names referenced in a proc are defined. Proc local is a special case of a call frame scope, being the nearest enclosing call frame scope.

channel scope is the per-interpreter global scope for resolving channel names e.g. stdin, file5. There is no eponymous command associated with channels (but it'd be easy enough to fudge.)

interp scope is an hierarchal global scope for resolving interpreters, not to be confused with the use of the command namespace for resolving the eponymous command associated with each interpreter.

package scope is a global for naming packages.


In summary, there are two major kinds of scoping in tcl - dynamic and lexical (or static) scope.

dynamic scope is accessed by default inside a proc, or by means of upvar with unqualified names, and is preferred for variable name resolution.

static or lexical scope is accessed explicitly by namespace encoded names, the global operator, and implicitly by command invocation and by the variable operator. Command resolution prefers dynamic scope.

RS has learnt this distinction, however:

  • dynamic scope determines variable value at runtime - used in older Lisp versions
  • lexical scope conserves the value of variables they had at the time a proc was defined, for instance in closures - considered more advanced in Lisp circles.

CMcC believes this isn't true. Firstly, closures can work in either lexically or dynamically scoped languages.

Secondly, Scoping is about how one resolves (or binds) free (or unbound) names. Dynamic binding can only occur at runtime, Static binding can sometimes occur at definition time (which is its supposed advantage).

In dynamically scoped languages (in, e.g. real Lisp :) the call frame is searched for name->value mappings matching some unbound name - like upvar. In lexically scoped languages (in, e.g. Scheme) the definition environment for the currently executing code is searched for those mappings - like tcl's variable


Some Dichotomies that Need Explaining

Variables (bindings from name to Tcl_Obj value) can be referenced by static and dynamic scopes. Procs and Commands can only be referenced by static scopes. Why is this? Much of the effort in considering and implementing lambda have to do with avoiding the consequences of this dichotomy.

The differences and similarities between Tcl_Objs and Commands is a fundamental and interesting topic. Tcl_Obj vs Command is a page to discuss it. - on reflection that page is misgiven CMcC 20041015


Category Concept