Namespace variables

Martin Lemburg: here some procedures ...

  • ... to get the full qualified name of ...
  • ... to check the existence of ...
  • ... to connect (with upvar) to ...

... a variable in the current or any parent namespace

 proc getFullNspcVarName {args} {
    switch -exact -- [llength $args] {
       1   {
          set nspc    [uplevel namespace current];
          set varname [lindex $args 0];
       }
       2   {
          foreach {nspc varname} $args {break;}
          
          if {[catch {namespace parent $nspc}]} {
             error "no such namespace \"$nspc\"";
          }
       }
       default   {
          error "wrong # args: should be \"getFullNspcVarName ?namespace? varname\"";
       }
    }
    
    while {![info exists ${nspc}::$varname]} {
       if {$nspc == "::"} {
          return "";
       }

       set nspc [namespace parent $nspc];
    }

    return ${nspc}::$varname;
 }

(See also [namespace which].)

Martin Lemburg:

no, "namespace which" is not comparable.

It doesn't do an recursive search over all parent namespace of the current or the given namespace.

There was a wikit-page Dynamic variable scoping with a procedure dynascope. This procedure provided access to variables in upper scope levels, with searching for the given variable in upper scope levels and upvaring it, if found.

The getFullNspcVarName procedure provides a similar support, for searching the given variable, but not in upper scope, but namespace "levels".

 proc varExistsInNspc {args} {
    if {[catch {set result [uplevel getFullNspcVarName $args]} reason]} {
       error $reason;
    }

    if {$result == ""} {
       return 0;
    }

    return 1;
 }

 proc nspcVar2LocalVar {args} {
    if {[catch {set result [uplevel getFullNspcVarName $args]} reason]} {
       error $reason;
    }

    if {$result == ""} {
       return 0;
    }

    set varname [namespace tail $result];

    if {[uplevel info exists $varname]} {
       error "namespace var \"$result\" already exists";
    }
    
    uplevel upvar $result $varname;

    return 1;
 }

 # demo and test:

 if {[file tail [info script]] == [file tail $argv0]} {
    namespace eval a {
       variable a1;
       variable a2;
       variable a3;

       set a1 "a1 is a var of ::a";
       set a2 "a2 is a var of ::a";
       set a3 "a3 is a var of ::a";

       namespace eval b {
          variable b1;
          variable a2;

          set b1 "b1 is a var of ::a::b";
          set a2 "a2 is a var of ::a::b";

          puts "varExistsInNspc b1    = [varExistsInNspc b1]";
          puts "getFullNspcVarName b1 = [getFullNspcVarName b1]";
          puts "varExistsInNspc a1    = [varExistsInNspc a1]";
          puts "getFullNspcVarName a1 = [set var [getFullNspcVarName a1]]";

          if {[nspcVar2LocalVar a1]} {
             puts "connected \"$var\" to \"a1\"";
             puts "a1 = $a1";
          } else {
             puts stderr "couldn't connect to \"a1\"";
          }

          nspcVar2LocalVar a2;
       }
    }
 }