52.tip at [6658788dee]

Login

File tip/52.tip artifact 20971c922a part of check-in 6658788dee


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.