Version 51 of namespace

Updated 2007-10-02 11:48:42 by Stu

namespace children ?namespace? ?pattern?

namespace code script

namespace code script

namespace current

namespace current

namespace delete ?namespace namespace ...?

namespace delete ?namespace namespace ...?

namespace ensemble option ?arg ...?

namespace eval namespace arg ?arg ...?

namespace exists namespace

namespace exists namespace output: namespace export ?-clear? ?pattern pattern ...?

'''[namespace forget]''' ''?pattern pattern ...?''
From 8.5 onwards, use this instead:
'''[namespace import]''' ''?-'''''force'''''? ?pattern pattern ...?''

namespace inscope namespace script ?arg ...?

namespace origin command list the variables in a namespace: namespace path ?list? --> new in Tcl 8.5 (TIP: [L1 ])

namespace parent ?namespace?

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

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

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

'''[namespace ensemble]''' is new functionality coming in a future release.

----

http://www.purl.org/tcl/home/man/tcl8.4/TclCmd/namespace.htm .  Also highly recommended is [William Duquette]'s tutorial [http://www.wjduquette.com/tcl/namespaces.html] on the use of namespaces and packages.  The "XML Namespaces FAQ" [http://www.rpbourret.com/xml/NamespacesFAQ.htm] has valuable background information on the general use of namespaces in computing, and [Sam Ruby] provides "A Gentle Introduction to Namespaces" [http://www.intertwingly.net/stories/2002/09/09/gentleIntroductionToNamespaces.html] for the [XML]-focused.

See also [_namespace import_ and _rename_] to appreciate the extraordinary freedom won through the use of namespaces.

list the commands in a namespace: Introspection and namespaces:

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

See "listns" and "Trivial procs" below.


Re-entering a namespace: Inside a namespace eval body, all namespace variables are visible at first. Inside a proc in the namespace eval body, they are hidden and must be explicitly made visible with the variable command.

However, it is possible inside a namespace to re-enter that same namespace by just saying

 namespace eval [namespace current] ...

This brings the namespace variables into sight, but the local variables of the proc are not visible - kind of like an uplevel effect for scope:

 namespace eval foo {variable grill 42}
 proc foo::bar {x} {
    namespace eval [namespace current] {
        concat $grill $x
    }
 }
 % foo::bar what
 can't read "x": no such variable

Namespace weirdnesses

ulis, 2003-11-16. Try this:

  set ::version 1.0
  namespace eval ns \
  {
    set version 0.9
  }
  puts $::version
  catch { puts $ns::version } msg
  puts $msg

Result:

  0.9
  can't read "ns::version": no such variable

Explanation:

As stated in the Tcl manual: 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.

In the above script the variable version wasn't defined inside the namespace so Tcl used the existing global variable.

To avoid that always define namespace variables with the variable command:

  set ::version 1.0
  namespace eval ns \
  {
    variable version 0.9
  }
  puts $::version
  catch { puts $ns::version } msg
  puts $msg

New result:

  1.0
  0.9

I (ulis) think that it would be better than the search in the global space was used when refering a variable and avoided when setting a variable.

Furthermore, when referring a variable or a proc in a namespace embedded in other namespaces, Tcl first searches the current namespace and then the global namespace (as documented) and doesn't look in any intervening embedding namespaces:

  proc ::p {} { puts "I'm ::p" }
  namespace eval ns \
  {
    proc p {} { puts "I'm ns::p" }
    namespace eval child \
    {
      p
    }
  }

Result:

  I'm ::p

Tcl resolved the name in the global namespace and didn't search in the intervening ns namespace.


JCW wrote in the comp.lang.tcl newsgroup: For variables, I've found a child namespace to be very 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).


Some simple proc to get all child namespaces recursively as a list:

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

  % 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

Trivial procs for getting variables, procs and commands defined inside a namespace:

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

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

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

They 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 ::).


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 all a namespace's content.


Is there a new subcommand called namespace upvar ?


LV 2007 June 11 - anyone have comments/suggestions/observations/warnings about the use of namespaces as the means to collect an application's data that is to be shared between procs and source files, as opposed to using global variables?


LV 2007 Aug 23 How would one introspectively interact with a namespace to determine what that namespace contains? That is, what procs, variables, or other namespaces reside within a namespace?

escargo - See the Trivial procs above. You use namespace children to look through the tree of namespaces, and info procs, etc., with namespace qualifiers to look for definitions in each namespace.


JeremyM 19 Sept 2007 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 19 Sept 2007 - 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.


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 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." 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 {} {} {
         for {set ns {};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.
 }


Category Command - Tcl syntax help - Arts and Crafts of Tcl-Tk Programming - Category Introspection