namespace path

namespace path ?namespaceList?

Returns the path of the current namespace, or sets it to the list of namespaces namespaceList if that argument is given.

The path of a namespace is used to “resolve” command names that do not start with a namespace qualifier (i.e., are not fully qualified) when those commands are not present in the current namespace.

Napier provides this little command to change the behavior of your command resolution to search up the namespace tree. Note that when using this, you will likely want to prefix your global commands with :: whenever possible so it doesnt have to resolve all the children.

proc setresolve { {depth 10} } {
        tailcall ::apply [list {depth} {
                set ns [namespace current]
                while { $depth > 0 } {
                        set ns [namespace parent $ns]
                        if { $ns eq "::" } { break }
                        namespace path [list {*}[namespace path] $ns]
                        incr depth -1
                }
        } [uplevel 1 {namespace current}] ] $depth
}

wdb This command shows or extends the namespace where an input command is searched in.

In this example, the namespace is extended:

% namespace path "tcl::mathfunc tcl::mathop"
% 

Now, you can input math-related commands as follows:

% hypot 3 [+ 2 2]
5.0
% 

In this example, the namespace extension is shown.

% namespace path
::tcl::mathfunc ::tcl::mathop
% 

Note that the namespaces argument is one proper list. It is not possible to input namespaces as single arguments. (Is it a matter of discussion if that should be possible?)

Note that each namespace (including the global namespace) has a different path. For example:

% namespace eval test {namespace path ::tcl::mathop}
%

inside newly created namespace test, path is extended to ::tcl::mathop. Now, check it out:

% namespace eval test {namespace path}
::tcl::mathop
%

Indeed, path is extended. Now check it in namespace ::

% namespace path
%

In namespace ::, obviously there is no path extension. Check if ::tcl::mathop::+ is known in namespace test:

% namespace eval test {+ 5 6}
11
%

Check the samein namespace :: leads to failure:

% + 5 6
invalid command name "+"
% 

JBR - 2011-12-23 — Unfortunately the current namespace is always checked, so its not possible to insert a bunch of commands to enhance and override the currently available commands, evaluate a block of code and then remove them. For instance, I have a mini language that I want to execute in the current variable context, but with with some domain specific commands:

   at atX 100

   draw {
        circle $atX 100 -radius 100
   }

I want draw to insert its dsl commands in to the current context and then evaluate the block of code using uplevel to retain the cosy user context, then remove its commands. Using namespace path might have been a nice thing here. But the current namespace is checked first during command resolution so I can enhance the command set but not override it. This is an issue in the global namespace where a lot of generic command names are already being used. So while not likely to be confronted with this in a namespace that you control, the question boils down to:

 "Is it possible to divert command resolution in the global namespace?"

Anyone have any ideas?

Thanks - John

DKF: IIRC, the current namespace is always checked first, and FQCNs always bypass the resolver. Use info vars to enumerate the visible variables and copy into another namespace or interpreter. (I use tricks like that in oo::define, and they seem to work well. OTOH, I don't try to map variables; I provide syntax that makes that normally unnecessary.)

JBR - Yes, the current namespace is always checked first, I'm just pointing out that setting up a namespace path is only a little useful and does not allow real control of command resolution as it might. I'm also aware of other convoluted and inefficient alternatives that might be used, its just I find them to be in bad taste compared to elegantly manipulating the namespace path, but alas its not implemented in a way which works well for this. My comments above reflect my exploration of what "the current namespace is always checked first" really means when you want to control what commands are actually called.

See also