TIP 229: Scripted Control of Name Resolution in Namespaces

Login
Bounty program for improvements to Tcl and certain Tcl packages.
State:		Final
Type:		Project
Tcl-Version:	8.5
Vote:		Done
Post-History:	
Author:		Donal K. Fellows <donal.k.fellows@man.ac.uk>
Created:	03-Nov-2004

Abstract

This TIP proposes extensions to the namespace command to allow scripts to control how individual namespaces map names to commands.

Rationale

Tcl has, for historic reasons, attracted many different styles of object system, and a favoured mechanism for implementing objects is on top of namespaces (which were introduced in Tcl 8.0 based on work done previously in [incr Tcl]). However, a common problem that these OO systems face is the inability to make namespaces efficiently map names of entities within classes etc. into the object instances. This TIP provides a simple mechanism for doing this.

No mechanism is provided for affecting the resolving of variable names. Best practice is to ensure that variables not present in the current namespace are imported explicitly through the upvar or variable commands (depending on context) and the fact that there is any possibility of non-local variable name resolution has been behind a number of bugs in the core (e.g. Bug #981733).

Proposed Change

Namespace Path Subcommand

The namespace command will gain a new subcommand, path, with the following syntax:

namespace path ?list?

This command sets and queries the current namespace's command name resolution path. If list is present, namespace path sets the path to the list of namespaces named in the list and returns the empty string; all the namespaces must exist or an error is thrown. If no list argument is provided, namespace path doesn't change anything and returns the current path.

Updates to Other Commands

The info commands command shall be updated so that, when no namespace is present in its pattern part, it shall return all (matching) commands that are visible without namespace qualifiers at this point. The info procs command will not be so modified.

Name Path Behaviour

Only names without a leading namespace separator in them are resolved using the namespace's path. When resolving command names, resolving relative to the current namespace is always preferred (unless a resolver is installed, of course), and resolution relative to the global namespace is always done after resolving relative to everything in the path (unless the global namespace is explicitly in the path, when it happens earlier). This means that the old behaviour is exactly what you get when the path is empty, and also ensures that virtually all scripts continue to work when a path is set; if it was possible to remove the global namespace from the actual path (as opposed to the settable part), virtually all scripts would break. If an extension installs a custom name resolver, that completely overrides the command name resolution path mechanism (to maximize backward-compatability; it is not anticipated that much code will try to mix the two mechanisms in a namespace).

Note that each namespace's path is isolated from the path of every other namespace, including the parent namespace. Systems using the namespace path mechanism as part of an implementation of inheritance will want to set up the path for each object namespace explicitly (this value can be statically precomputed on a per-class basis); indeed, where multiple inheritance is involved it will probably be more efficient to compute the path than let Tcl guess.

The path is parsed completely at the time the namespace path command is run, and the resulting list of namespaces is used directly. If a namespace on some namespaces' path is deleted, it is immediately excised from the path of every namespace that refers to it.

Examples

The following script returns "::foo":

namespace eval ::foo {
   proc boo {} {namespace current}
   namespace eval bar {
      namespace path ::foo
      boo
   }
}

The following script return "::foo::bar":

namespace eval ::foo {
   proc boo {} {namespace current}
   namespace eval bar {
      proc boo {} {namespace current}
   }
   namesspace eval spong {
      namespace path ::foo
      bar::boo
   }
}

Implementation

A patch is availablehttp://sf.net/tracker/?func=detail&aid=1159942&group_id=10894&atid=310894 .

Copyright

This document has been placed in the public domain.

History