TIP: 52
Title: Hierarchical Namespace Lookup of Commands and Variables
Version: $Revision: 1.6 $
Author: David Cuthbert <[email protected]>
Author: Andreas Kupries <[email protected]>
State: Withdrawn
Type: Project
Vote: Pending
Created: 09-Aug-2001
Post-History:
Discussions-To: news:comp.lang.tcl
Keywords: namespace,lookup,hierarchy
Tcl-Version: 8.5
~ Abstract
This TIP proposes to change the command and variable namespace lookup
system so that the full hierarchy of namespaces is parsed, rather than
just the current namespace followed by the global namespace. This is
primarily intended to rectify problems often encountered with the use
of [[incr Tcl]] (ITcl) and namespaces. In addition, package
encapsulation can be enhanced with judicious application of this
feature.
~ Rationale
Currently, the following code is invalid in Tcl/ITcl:
|package require Itcl
|
|namespace eval SampleNS {
| proc Hello {} { puts "Hello world!" }
|
| ::itcl::class X {
| public constructor {} {} { Hello }
| }
|}
|
|SampleNS::X x1 ;# Error: invalid command name "Hello"
This is due to the fact that ITcl classes double as namespaces.
Therefore, the lookup of ''Hello'' takes place first in
''::SampleNS::X'', followed by ''::'' (the global namespace).
The current workaround - to reopen the class' namespace and issue a
''namespace import'' directive - is of limited value since ''namespace
import'' is not capable of bringing in names defined later on. The
following code illustrates this point:
|package require Itcl
|
|namespace eval SampleNS {
| ::itcl::class X1 {
| public method GetSibling {} { return [X2 \#auto] }
| }
| namespace eval X1 { namespace import ::SampleNS }
|
| # Further down, or perhaps in a separate file source later:
|
| ::itcl::class X2 { }
|}
|
|set x [SampleNS::X1 \#auto]
|$x GetSibling ;# Error: invalid command name "X2"
Non-ITcl code can also make use of hierarchical namespaces to better
encapsulate support procedures. In this example, the child namespace
''private'' illustrates that the ''GetUniqueId'' procedure should not
be used outside of the package; however, ''GetUniqueId'' still has
access to the procedures and variables in the package's main
namespace:
|# MyPackage
|
|namespace eval MyPackage {
| variable nextId 0
|
| namespace eval private {
| proc GetUniqueId {} {
| variable nextId
| return "MyPackage.[incr nextId]"
| }
| }
|
| proc CreateObject {} {
| set name ::[private::GetUniqueId]
| proc $name args { body }
| return $name
| }
|}
~ Specification
Currently, the ''NAME RESOLUTION'' section of the ''namespace''
documentation states:
> If the name does not start with a :: (i.e., is ''relative''), Tcl
follows a fixed rule for looking it up: Command and variable names
are always resolved by looking first in the current namespace, and
then in the global namespace. Namespace names, on the other hand,
are always resolved by looking in only the current namespace.
The proposed change to this is as follows:
> If the name does not start with a :: (i.e., is ''relative''), Tcl
follows a fixed rule for looking it up: Command and variable names
are always resolved by traversing the namespace hierarchy - that
is, the current namespace is examined first, followed by the
parent, the parent's parent, and so on, until (finally) the global
namespace is examined. Namespace names, on the other hand, are
always resolved by looking in only the current namespace.
By keeping the current behaviour for namespace names, this TIP affects
only completely unqualified commands and variables (i.e. those that do
not contain ::). Changing the behaviour of partially qualified names
(those that are relative ''and'' contain ::) is often unintuitive and
can lead to unexpected errors.
~ Consequences
1. ITcl classes and child namespaces can refer to command and
variable names in their parent hierarchy without requiring the
names to be fully qualified. This improves the intuitiveness and
readability of Tcl code. In addition, it can reduce the
brittleness of the code should parent namespace names undergo a
change (e.g., ''namespace eval scriptics.com'' to ''namespace eval
ajubasolutions.com'').
2. Currently well-defined behaviour is modified. This can break
existing code if the following conditions are met:
> * The code employs the use of namespaces with a depth greater than
one below the global namespace.
> * The code creates a variable or procedure in a parent namespace
with the same name as a variable or procedure in the global
namespace.
> * The code in the child namespace uses unscoped names to refer to
commands and/or variables in the global namespace.
> A cursory examination of existing Tcl code available on the
Internet revealed no code which used deeply nested namespaces.
3. Existing well-defined behaviour of the internal Tcl function
''TclGetNamespaceForQualName'' is modified. Under the sample
implementation, the ''altNsPtrPtr'' parameter (which currently
returns a pointer to the global namespace if a name was found
there) always returns NULL. It is up to the calling functions
(e.g., Tcl_FindCommand and Tcl_FindNamespaceVar) to traverse the
hierarchy. Although the Tcl and Tk code-base can be modified to
accommodate this, extensions which depend on this internal
function may be broken.
~ Namespace History
Namespaces were originally developed by Michael McLennan for ITcl, and
apparently had this hierarchical resolution feature. When they were
adopted into Tcl, an optimisation was made which led to the current
behaviour.
This TIP argues for the reversal of this decision based on experiences
with the new behaviour.
~ See Also
* Tcl manual page ''namespace''.
* Tcl source code file ''tcl8.4a3/generic/tclNamesp.c''.
* Sample implementation at http://www.kanga.org/tclnamespace/
~ Comments
* Andreas Kupries:
> Related information: SF entry [[ #218101 ]] "no man page for library procedures Tcl_AddInterpResolver Tcl" [http://sourceforge.net/tracker/?func=detail&aid=218101&group_id=10894&atid=110894]
> Not addressed in this TIP: Impact on speed of the interpreter.
(Seeking out mail on Tcl core where author of talks about this)
~ Notice of Withdrawal
This TIP was Withdrawn by the TIP Editor following discussion on the
tcl-core mailing list. The following is a summary of reasons for
withdrawal:
> Insufficiently subtle. 52 will break any code that assumes the
current behaviour (and you can bet someone will have that
assumption) and 142 doesn't let two namespaces have different
search paths (unless the variable is always interpreted locally,
which just creates bizarre variable name magic.)
~ Copyright
Copyright � 2001 by David Cuthbert. Distribution in whole or part,
with or without annotations, is unlimited.