George Peter Staplin Dec 28, 2005 - I've been working on a project that needed to avoid infesting the global namespace with unprefixed names, so an obvious solution was to use
namespace. However I can't do that as easily with
ProcMeUp, so I came up with an alternative solution that is also in my opinion superior, and simpler than using
namespace (for some uses).
Why do I consider this superior? It allows creating a namespace that is named whatever the
user desires, rather than what the package designer chose.
The concept is simple. You prefix each proc with
NS_ and each global with
NS_.
NS_ is unlikely to occur in any other normal sequence, however of course it could be called something else.
proc NS_foo {a b c} {
global NS_var
set NS_var [list $a $b $c]
}
How does this allow the user to dynamically decide the namespace?Let us imagine that the code above is in foo.tcl then we could do this (if foo.tcl is in the same directory as the current script):
set fd [open [file join [file dirname [info script]] foo.tcl] r]
eval [string map {"NS_" "super_"} [read $fd]]
close $fd
That could all be factored into a proc such as source.namespace. For example:
proc source.namespace {f ns} {
set fd [open $f r]
#
# We use uplevel 1 to eval in the parent's scope.
#
uplevel 1 [string map [list "NS_" $ns] [read $fd]]
close $fd
}
source.namespace [file join [file dirname [info script]] foo.tcl] super_
So by now thanks to the
string map we have:
proc super_foo {a b c} {
global super_var
set super_var [list $a $b $c]
}
This is also an easier way to update old packages, or code not designed for namespaces. Thus making it possible to bring that code into an environment where previous global variables or proc names would be problematic.
SLB Interesting. I had been thinking about new ways to use namespaces and have written up some thoughts in
Local Packages and Transparent Namespaces.