Question

I saw some code in TCL like this:

namespace eval ::info {
    set count 0;
    set id 1;
    set role admin;

    namespace export *
}



proc ::info::setcount {
    set ::info::count 0;
}

proc ::info::setId {
    set ::info::id 1;
}

proc ::info::setRole {
    set ::info::role user;
}

There are three variables defined in namespace ::info, but that three procs(setcount setId setRole) are not declared in the namespace, seems like they are defined outside of ::info, is this allowed? how does this work?

Was it helpful?

Solution

The procedures are defined in the ::info namespace. They're just not inside the scope of the namespace eval, a command that just creates the namespace if necessary and then executes the given script within that context. Being executed within the context of a namespace changes how proc places commands that it creates when the names of those commands are not fully-qualified. The namespace exists independently of the namespace eval call. The variables have to be declared in the namespace though; that avoids some really nasty trouble with resolution of variables that can catch people out.

Personally, I prefer to write code like this:

namespace eval ::foo {
    proc bar ... {
        ...
    }
}

But I know that other people disagree with me. Write what you prefer, as Tcl works just fine with either scheme.

OTHER TIPS

The namespace eval command

  1. Creates the namespace if it doesn't exist
  2. Runs the code supplied to it from within that namespace

Procs defined from within a namespace (which is all procs, since the default namespace is ::)

  • If preceded by an absolute namespace, will define that command in the specified namespace
  • If preceded by a relative namespace, will define that command relative to the current namespace

As such

namespace eval bob {
    namespace eval joe {
        proc proc1 {} {}
    }
    proc proc2 {} {}
    proc ::proc3 {} {}
    proc joe::proc4 {} {}
}
proc proc5 {} {}
proc bob::joe::proc6 {} {}
proc ::bob::joe::proc7 {} {}

The following commands will exist

::bob::joe::proc1
::bob::proc2
::proc3
::bob::joe::proc4
::proc5
::bob::joe::proc6
::bob::joe::proc7

Notice that commands in the global namespace, when called from the global namespace, can be preceeded by a :: or not. The same is true of commands in any namespace.

namespace eval bob {
    proc2 ;# calls ::bob::proc2
    ::proc5 ;# calls ::proc5 (proc5 in the global namespace)
    joe::proc4 ;# calls ::bob::joe::proc4
}

It is worth noting that a raw command name (with no namespace qualifiers at all) will look in the current namespace and then, if it doesn't find the command there, the global namespace.

namespace eval bob {
    proc5 ;# calls ::proc5 since there is no ::bob::proc5
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top