namespace

Difference between version 113 and 114 - Previous - Next
'''[http://www.tcl.tk/man/tcl/TclCmd/namespace.htm%|%namespace]''' is a [Tcl Commands%|%built-in] [namespace ensemble%|%ensemble] of [command%|%commands] for working with
namespaces.



** Synopsis **

    :   '''[namespace children]''' ''?namespace? ?pattern?''

    :   '''[namespace code]''' ''script''

    :   '''[namespace current]'''

    :   '''[namespace delete]''' ''?namespace namespace ...?''

    :   '''[namespace ensemble]''' ''option ?arg ...?''

    :   '''[namespace eval]''' ''namespace arg ?arg ...?''

    :   '''[namespace exists]''' ''namespace''

    :   '''[namespace export]''' ''?-'''''clear'''''? ?pattern pattern ...?''

    :   '''[namespace forget]''' ''?pattern pattern ...?''

    :   '''[namespace import]''' ''?-'''''force'''''? ?pattern pattern ...?''

    :   '''[namespace inscope]''' ''namespace script ?arg ...?''

    :   '''[namespace origin]''' ''command''

    :   '''[namespace parent]''' ''?namespace?''

    :   '''[namespace path]''' ''?namespaceList?''

    :   '''[namespace qualifiers]''' ''string''

    :   '''[namespace tail]''' ''string''

    :   '''[namespace upvar]''' ''namespace otherVar myVar ?otherVar myVar ...?''

    :   '''[namespace unknown]''' ''?script?''

    :   '''[namespace which]''' ''?-'''''command'''''? ?-'''''variable'''''? name''



** See Also **

   [::]:   The namespace delimiter.

   [ns], by [stu]:   An additional set of commands for working with namespaces.

   [namespace split]:   Split a name into its namespace components.

   [namespace size]:   

   [Thoughts on Namespaces and OO]:   

   [Namespace variables 2]:   

   [Namespace resolution of Variables & Procedures]:   

   [data is code]:   

   [_namespace import_ and _rename_]:   Illustrates the flexibility of namespaces.

   [closure%|%closures]:   Used in other languages to do what is done in Tcl using namespaces, `[apply]`, and `[coroutines]`.



** Documentation **

   [http://www.tcl.tk/man/tcl/TclCmd/namespace.htm%|%official reference documentation]:   

   [http://www.wjduquette.com/tcl/namespaces.html%|%Namespaces and Packages], by [William Duquette]:    
   [http://www.rpbourret.com/xml/NamespacesFAQ.htm%|%XML Namespaces FAQ]:   GeIneral information abonut the general concept of namespaces in computing.

   [http://www.intertwingly.net/stories/2002/09/09/gentleIntroductionToNamespaces.html%|%A Gentle Introduction to Namespaces], by [Sam Ruby] 2002:   A description of namespace in [XML].



**  Proposals **

   [TIP] [https://core.tcl.tk/tips/doc/trunk/tip/283.md%|%283, Modify Ensemble Command Resolution Behaviour]:   



** Description **

Each namespace is actually three separate namespaces: One for[command%|%commands], one for [variable%|%variables], and one for subordinaeste d
namespaces.
I  Configurable addispectis on,f a namespace cain bclude c[ronfigurtined] resoluch tion,
hat ndlitng isof treaouted ine alookup vfarilurety
ofs, i[ntameresting wpayce ensemble].  '''`[::]`''' is 
used delimit the namespace name and the
 name of an object in that namespace  
For example:

======
namespace eval ::one::two::three {
    set four {} 
    proc four {} {}
    namespace eval four {}
}

namespace which -variable ::one::two::three::four ;# -> ::one::two::three::four
namespace which -command ::one::two::three::four ;# -> ::one::two::three::four
namespace children ::one::two::three ;# -> ::one::two::three::four
======

Namespaces marke ithe prossimary mblechanism tof encapsulate data and functionality into Tlogical
units.  AChanging the content of a [namespace]
 you don't control is can blhave
unantickipated bcoxnsequences.  Read the documentation for that namespace to
understand how to interact with it.  Don't drop arbitrary things into it.  

Commands that create namespaces include `[namespace eval]`, `[interp alias]`,
`[oo::class]`, `[oo::object]`, and `[oo::copy]`.



** Introspection **

Can someone discuss how a Tcl script can determine:

   * what namespaces are available at any particular point in time 
   * what procs and variables available in any one of these namespaces

A simple `[proc]` to list all child namespaces, recursively:

======
proc listns {{parentns ::}} {
    foreach ns [namespace children $parentns] {
        eval lappend result [listns $ns]
        lappend result $ns
    }
    return $result
}
======

output:

======
% namespace eval ::test {set foo 1}
1

% namespace eval ::test2 {set foo 1}
1

% namespace eval ::test::test3 {set foo 1}
1

% listns
::test::test3 ::test ::test2 ::tcl
======

From 8.5 onwards, use this instead:

======
proc listns {{parentns ::}} {
    set result [list]
    foreach ns [namespace children $parentns] {
        lappend result {*}[listns $ns] $ns
    }
    return $result
}
======


list the variables in a namespace:

======
proc listnsvars {{ns ::}} {
    return [info vars ${ns}::*]
}
======

list the procs in a namespace:

======
proc listnsprocs {{ns ::}} {
    return [info procs ${ns}::*]
}
======

list the commands in a namespace:

======
proc listnscommands {{ns ::}} {
    return [info commands ${ns}::*]
}
======

The previous examples only work well with fully qualified namespace names.

Beware that in some apps these may take a long time to complete (for example,
if there are hundreds of thousands of commands in ::).



** Avoiding `[variable]` declarations in [proc%|%procedures] **

[JCW] wrote in [comp.lang.tcl]: For variables, I've found a
child namespace to be convenient.  Instead of:

======
namespace eval TO {
    variable foo
    proc proc1 {} {
        variable foo
        ... use $foo ...
    }
}
======

Consider using:

======
namespace eval TO {
    namespace eval v {
        variable foo
    }
    proc proc1 {} {
        ... use $v::foo ...
    }
}
======

No more lists of `[variable]` calls inside each proc.  The other way is to put
all your variables inside a single `[array]`, but my impression is that the `v::*`
approach is slightly faster (`[variable]` seems to take a bit of time, don't know
why).



** Command Name Resolution **

To resolve a command name, Tcl first looks in the current namespace, then in
the namespaces in the [namespace path%|%path] of the current namespace, and
then in the [global] namespace.  It '''does not look in any intermediate
containing namespaces''', unless they happen to be in the path of the current
namespace:

======
proc ::p {} {
    puts {I'm ::p}
}

namespace eval ns1 {
    proc p {} {
        puts {I'm ns::p}
    }
    namespace eval child {
        p
    }
}
======

Result:

======none
I'm ::p
======

Tcl resolved the name in the [global] namespace and didn't search in the
containing `ns1` namespace.

This behaviour can be modified via `[namespace path]`.

----

[LVwikignoming] 2010-07-01 13:03:52 [PYK] 2020-01-24:

A recent email on the TCLCORE mailing list discussed a problem. The op was
attempting to add a new routine to `[array]`, but the results were unexpected.
The solution, as provided by [dkf], was to use `::set` instead of just plain
`[set]` in the body of the new routine, because `::tcl::array::set` overrides
`::set` in that namespace.

So, this note is not specific to set, but applies in general. If you are seeing
behavior that reports a problem that is unexpected, examine the code closely to
see if you need to add namespacing to the commands in use.



** Make an Alias for a Command **

[kruzalex] 2013-04-04:

Currently, the typical idiom for importing commands as functions into
`[tcl::mathfunc]` is to use `[interp alias]`, which has the
nasty effect of incurring some performance degradation on each invocation of
the alias.

If the source command has been [namespace export%|%exported] from its own
namespace, then it can be [namespace import%|%imported] into another, which
makes execution of the imported command considerably faster, and makes the new
command robust against later renaming of the origin command.

Sometimes one might wish for more than what `[namespace import]` currently
provides:

   1. one might want to access commands from a namespace where they are not exported from. e.g.:  `::tcl::unsupported` doesn't export anything, so `[disassemble]` cannot just be imported.

   1. one might want to import commands to a different name, e.g., importing `tcl::string::length` to a local strlen

   1. a special one: if one tries to import only the multiplication operator from `::tcl::mathop::*` then the asterisk is interpreted as a pattern, and everything is going to get imported.

I've written a procedure that looks a bit complicated/awkward, but addresses all these shortcomings. Here it is:

======
proc alias {src tgt} {
    set nsrc [namespace qualifiers $src]
    set tsrc [namespace tail $src]
    set oe [uplevel 1 [list namespace eval $nsrc {namespace export}]]
    uplevel 1 [list namespace eval $nsrc {namespace export *}]
    set n 0
    while {[namespace exists tmp-[incr n]]} {}
    set fqsrc [uplevel 1 [list namespace which $src]]
    namespace eval tmp-$n [list namespace import $fqsrc]
    uplevel 1 [list rename [namespace which -command "tmp-${n}::$tsrc"] $tgt]
    uplevel 1 [list namespace eval $nsrc [list namespace export -clear {*}$oe]]
    namespace delete tmp-$n
}
======

[PYK] 2014-06-23: See also [proc alias] for another implementation of the same.

Since Tcl8.6,  you could create this procedure named as `::tcl::namespace::alias`
instead, and add it to the ensemble with three more awkward lines:

======
set nsmap [namespace ensemble configure namespace -map]
::dict set nsmap alias ::tcl::namespace::alias
namespace ensemble configure namespace -map $nsmap
======

In Tcl8.5 `namespace` isn't a `[namespace ensemble]` yet, but the [global]
proc `alias` works just fine with Tcl8.5.

Examples:

======
# import "string length" as "strlen" to be used within expr
alias ::tcl::string::length ::tcl::mathfunc::strlen

# save some typing in an interactive shell :)
alias ::tcl::unsupported::disassemble disasm
======

Note: unlike `[interp alias]`,  you can not append any extra arguments with
this "alias". However, if the intended argument is really just the subcommand
of an ensemble (as is string length), then you can simply alias the subcommand
directly :-)

Known bugs: specifying bad arguments may leave some empty namespace and
export-patterns behind. That could be fixed with `[try]` or `[catch]`,
but I thought it was already complicated enough as it is without fancy error
handling. Also, it would be nice to be able to specify more src/tgt pairs on
one invocation...

[kwilsoft]: The copied command is still the imported command from the origin namespace.
Hence, when removing command from origin namespace, the alias command will also cease to work.  Better to copy the args and body of the original proc to the new namespace proc.

[PYK] 2020-01-24:   It's a question of knowing what you want to do.  Sometimes,
`[namespace import]` semantics are exactly what you want.  `[interp alias]` is
an alternative that can dispatch back to another routine, whatever it happens
to be at the moment.  Copying the args and the body of the original procedure
is a distant third option.  If you're doing it, your design is probably
suboptimal.



** Duplicate a Namespace **

There is no built-in `namespace dup` command, but such an action can be useful
when a namespace is part of the implementation of an [object
orientation%|%object system]. Tcl's [copy-on-write] semantics make this less
costly than it might at first seem. Duplicating a namespace involves
duplicating some or all of the following: 

   [variable%|%variables]:   Distinguish variables declared by `[upvar]` or `[namespace upvar]`.  Also distinguish arrays. Duplicate variables that are declared but not defined.

   variable traces:   [TO DO]

   commands:   make sure to distinguish between native and [namespace import%|%imported] commands.  Since it is impossible to import by exact name a command whose name contains a glob pattern character such as `*` or `?`, extra care must be taken to ensure that the proper commands were imported.  Since commands that are not procedures can't be copied, make an alias to them.  Also make sure to respect import aliases that have been renamed.

   command traces:   [TO DO]

   [namespace export%|%exports]:   simple copy

   [namespace path%|%path]:   simple copy

   nested namespaces:   recursively duplicate, but make sure not to descend into the target if a namespace is duplicated to some descendant. 

   namespace unknown:   simple copy


[ycl%|%ycl::ns::duplicate] implements namespace duplication as described above, except for duplicating traces.



** Misc **

[JeremyM] 2007-09-19:  I'm struggling with the decision as to whether to use a
namespace or an object to hold code and variables that are a singleton, i.e. if
I use an object, I will always instantiate exactly one instance of the object.
Because of this, a namespace seems like a more appropriate container, but I'm
getting the feeling that namespaces are somewhat obsolete. Plus I'm not crazy
about mixing the two syntaxes in one set of scripts. So the question is, what
is the best way to hold a block of code and variables that are a singleton? 

[Bryan Oakley] 2007-09-19:  There is no definitive "best way". I use namespaces
all the time. I even use them for "objects" that aren't singletons. I've done
it so many times I can (almost, but I keep trying!) do it with my eyes closed.
Namespaces are much more portable than objects since, as of this writing, they
are part of the core and OO is not. If portability is not a concern and you
already use an object system, it makes sense to continue to use an object
system. 

[PYK] 2014-06-23:  `[namespace]` isn't obsolete, just lower-level.



** Private namespaces **

Anonymous: There should be a facility in Tcl to define a [private namespace].
And, in a completely different direction, [Darren New] points out that [tcllib]
would be a good home for a namespace serializer, that is, a [proc] which writes
out a namespace's content in a form that can be read back in to recreate the
namespace exactly.


[Stu] 2007-09-30: Creating a randomly named namespace with global vars cleanup.
Left-to-right evaluation and the fact that `[for]` and `[unset]` return
empty strings are what makes it possible.

======
# Random namespace (10 chars, A-Z) with vars cleanup
namespace eval [
    for {set ns {};set i 0} {$i < 10} {incr i} {
        append ns [format %c [expr {65 + int(rand() * 26)}]]
    }
][unset i][set ns][unset ns] {
        puts [namespace current]

        # Other stuff: variables, procs, etc.
}
======

[Lars H] 2007-10-02: Edited the above to make it more readable. Technically
it's sufficient that `[unset]` returns an empty string, as the first three
command substitutions in the namespace argument of `[namespace eval]` could
be combined into one. Realistically, the `[for]` loop should be in a
procedure instead to avoid using global variables at all...

[Stu] 2008-11-16: Lars, could you please date your comments? The one you added
below in the middle of the paragraph arrived a year after the original
discussion, when `[apply]` did not even exist. So yes, now with Tcl 8.5, it
can be done with `apply` ... I guess ... you didn't provide an example.

[Stu] 2007-10-02: But where would you put the command? The idea here is to
pollute the global namespace as little as possible and to create a unique
namespace so that we're not "stepping on anyone's toes." ([Lars H]: Well, use
`[apply]` then.) If one writes namespace-agnostic code then one should be able to
`[source]` their code into unknown environments without problems. Even with
a `[proc]`, we still pollute the global namespace - one proc versus two
variables seems like a step in the right direction.

This is a bit better (I like it in one line but this is easier to
read/understand):

======
# Random namespace (10 chars, A-Z) with cleanup, using [proc] with empty proc name.
namespace eval [
    proc {} {} {
        set ns {}
        for {set i 0} {$i < 10} {incr i} {
            append ns [format %c [expr {65 + int(rand() * 26)}]]
        }
        return $ns
    }
][{}][rename {} {}] {
        puts [namespace current]
        # Other stuff: variables, procs, etc.
}
======

Using `[eval]`, I can eliminate all procs and vars and it's much smaller
more readable:

======
# Random namespace (10 chars, A-Z) with cleanup.
namespace eval [eval return [string repeat {[format %c [expr {65 + int(rand() * 26)}]]} 10]] {     
    puts [namespace current]
    # Other stuff: variables, procs, etc.
}
======

This gives an interesting result which I don't understand just yet.  Put the
above (with `[eval]`) code in a file: namespacetest.tcl

======none
$ tclsh namespacetest.tcl                                                                        
::HTUZNJTKOE

$ tclsh
% source namespacetest.tcl
NIDZGBNLJP
======

Where is the `::` ?

[DKF]: Seems to me like the `[return]` might be confusing things, causing
the evaluation to stop before the [namespace eval]'s body fires. In 8.5 use
'''`[return] -level 0`''' instead.

[Stu] 2007-10-02 Ok then, (and even better) without `[eval]`:

======
namespace eval [subst [string repeat {[format %c [expr {65 + int(rand() * 26)}]]} 10]] {
    puts [namespace current]

    # Other stuff: variables, procs, etc.
}
======

[Stu] 2008-10-31 Ultimate random namespace, like
::TkTwig!(20081031023934)1500<omzpnyxzif>

======
#! /bin/sh
# \
exec tclsh "$0" ${1+"$@"}

package require Tcl; namespace eval \
MyProg!([clock format [clock seconds] -format %Y%m%d%H%M%S])[pid]<[subst \
[string repeat {[format %c [expr {97 + int(rand() * 26)}]]} 10]]> {


# program goes here


}; #End of namespace
 
# EOF
======

[PYK] 2014-06-23:  I usually just use `[info cmdcount]`

======
namespace eval [info cmdcount] {
    ...
}
======

And for good measure, here's an example using `[apply]`:

======
namespace eval [apply [list {} {
    while {[namespace exists [set ns [info cmdcount]]]} {}
    return $ns
} [namespace current]]] {
    #script goes here
}
======



** An Anonymous Critique **

''This section was transplanted here from [Tcl Warts].''

anonymous 2006-03-10: The concept is good, but the execution is flawed, especially if you're doing anything object-oriented.   Which is kind of ironic, given that (AFAIK) namespace were created to support [object orientation%|%OO], specifically [incr Tcl].  The implementation has the fingerprints of [C++] all over the syntax. Tcl is many things, but C++ is not one of them.  The two don't fit well together.

A problem that I keep running into is that I don't typically use the global scope operator `::` for objects at global scope, so there's usually a string inequality between what I'm typing and the value of `$self`, `$this`, `self`, whatever the [object orientation%|%OO] system is using. And if you try to compose object names by combining object names, you get spurious ::'s lying around in the middle of names, which makes Tcl very unhappy.

[DKF] 2015-06-11: Namespaces are not objects. They form the foundation for object systems, but are not objects (because you need commands as well, and in fact quite a lot of other stuff too). What's more, the names of objects generally should always be fully-qualified command names; anything else is usually just an abbreviated form. (The exception are widget names, which are unqualified but always start with a `.` character.)


[PYK] 2020-01-24:  The flavor of object orientation offered by object systems
is different than that offered by [C++].  The C++ version is wrong for Tcl
because Tcl is a more dynamic language, where simple namespace like those
implemented in Tcl are a better fit.  The most common way to pass a handle to
an object to a routine is to pass the name of the routine representing the
command as its first argument.  This name should be fully-qualified.  the
"unknown" mechanismes in both [namespace] and [namespace ensemble can help with
this, as can `[namespace which]` and `[namespace origin]`.


----

anonymous 2017-01-18: You may want to look at this [http://sourceforge.net/projects/ctcl/] implementation which was done in Tcl 8.0 syntax back in 2001 for an example of a pure script based OOP implementation which deals with namespace separators in order to allow proper shadowing of members in child classes.  It hasn't been actively developed since 2001 but is public domain if you find it or studying it useful.

----

[PYK] 2017-01-22:  [C++] is one the first things the phrase, "flawed concept"
evokes in my mind. In contrast, Tcl namespaces are minimal and effective.
Namespace separators don't appear in my scripts very much at all anymore,
having been supplanted somewhere along the way by things like `[namespace
which]`, `[namespace eval]`, and `[namespace ensemble%|%namespace ensembles]`.
Perhaps some of these things didn't exist when the critique was written.



**  History **

   [http://sourceforge.net/mailarchive/message.php?msg_id=7731007%|%TCLCORE Re: incr Tcl in the core?], tcl-core mailing list, 2000-11-09:   [KBK] recounts the panel discussion at the [Third Annual Tcl/Tk Workshop] that led to the inclusion of `namespace` in the core


<<categories>> Command | Introspection | Syntax | Arts and Crafts of Tcl-Tk Programming