tcl

namespace inside another namespace or 2 distinct namespaces : the result is the same


I don't see the difference between the 2 scripts.

# First script
namespace eval ns1 {
    namespace eval ::ns2 {
        proc name {} {
            puts ok
        }
    }
}
# Second script
namespace eval ns1 {}
namespace eval ns2 {
    proc name {} {
        puts ok
    }
}

In both cases, calling the name procedure is the same writing. My example is very simple, but I thought that my first script protected the ns2 namespace and that I could call the name command only if the ns1 namespace existed.
My apprehension is to have the same namespace ns2 in another package, source... for example.


Solution

  • Both of your scripts create the proc in the ::ns2 namespace. In your first script, you prefixed the ns2 with (::), which means it is created relative to the root namespace (and not relative to the wrapping ns1 namespace), thus essentially ignoring the outer ns1 namespace.

    Your second script also creates the proc in the ::ns2 namespace. The first line (namespace eval ns1 {}) does nothing. Because the second line is run in a global context it creates the ns2 namespace as a child of the global namespace i.e. your ns2 is equivalent to ::ns2.

    You can confirm this by running it with the full namespace or with info command e.g.

    % ::ns2::name
    ok
    % info command ::ns2::name
    ::ns2::name
    

    If you want to create your proc in ns2, where ns2 is a child namespace of ns1, just omit the double colon e.g.

    namespace eval ns1 {
        namespace eval ns2 {
            proc name {} {
                puts ok
            }
        }
    }
    
    % ::ns1::ns2::name
    ok
    % info command ::ns1::ns2::name
    ::ns1::ns2::name
    

    In order to run the name proc, you will need to provide the full namespace either explicitly or in an eval. If you just try to run name, you get a namespace error:

    % name
    wrong # args: should be "namespace subcommand ?arg ...?"