Tcl namespaces can be invaluable for separating code into managable
units. However complexity due to coupling
quickly increases due to an explosion of
namespace-prefixes.
The solution normally is to make use of [namespace import].
However, this requires dealing with other issues, eg:
Command name collisions
Load-ordering dependancies.
Collisions are a problem when local command definitions either cause an
import to fail, or if -force is used, commands to get overwritten.
Load order refers to the requirement for explicit imports before using a command.
Dealing with these increases code complexity, fragility and unmanagability.
The uses command provides an alternative offering
on-demand management of imports for a namespace.
2. Usage
The uses command sets-up the calling namespace with
dynamic, on-demand importing. By default, the namespaces
are assumed to be Modules defined with Mod export.
namespace eval ::myns {
uses ::lib::x ::lib::y
x subcmd1 ...
x subcmd2 ...
y subcmd3 ...
}
However, using the ^suffix flag one can autoimport and access the sub-commands themselves.
That is, it allows one namespace to use commands from another namespace
without namespace prefixes or explicit imports.
Uses helps leverage Tcl's high degree of structure that namespaces offer,
while providing users with ease of use similar to that of
big-bag-of-functions languages such as PHP.
By default uses will place auto-imports
into the current namespace.
Changing this, however is easily done by append a
target namespace after an @ sign. The most common target
is the @:: meaning the global namespace.
This is where Tcl builtin subcommands end up in Mod.
This example specifies, importing ::lib::x and sub-commands of
::lib::y into the :: namespace.
If all arguments to ''uses' are to have the same target and options (see below), use
make
first entry starts with an = (or +=) followed by the targets and flags for all.
For example, the following are equivalent
Normally later calls to [uses] take precedence over earlier definitions.
To make later uses be fallbacks,
make the first argument to uses a plus sign "+". eg.
namespace eval ::myns {
uses + ::lib::x
}
after which existing definitions take precedence, meaning that ::lib::x
will not override Tcl builtin sub-commands. Note the "+" may also be used as
a prefix to a
target prefix.
5. Uses Flags
The following flags may be appended to any namespace used with [uses]:
CH
DESCRIPTION
^
Autoimport subcommands from the namespace
&
Inherit uses definitions from namespace
5.1 Inherit uses: "&"
The "&" suffix flag inherits the uses specification from the specified source namespace.
This is commonly used with the ".." namespace shortcut to ensure
access to any command available in the parent namespace.
5.2 Sub-Commands: "^"
The "^" suffix flag is used to indicate that subcommands of the namespace
are to be auto-imported.
Normally, a uses applies to the module command,
or in the case of TOD just loading of the module.
This flag is implied in the ".." namespace shortcut.
6. Source File Loading and "mod_index"
A namespace can use mod_index to locate it's files
and source and/or load them automatically.
Elements of the array mod_index are indexed by a fully qualified namespace.
The value assigned is a list, of the form:
FLAG DIR FILE CMDS FILE CMDS ....
The directory name
roots the source files. Usually this is just $dir, but alternatively one can just use [info script].
The file items are expected to be source and/or shared library files.
And the cmds are the list of commands created therein.
The file extensions determine which command is used, source or load.
# The modIndex.tcl file for lib::x
set mod_index(::lib::x) [list 1 $dir file1.tcl {foo bar} subdir/file3.tcl {cat dog} mylib.so {pig bat}]
The modIndex files are normally located in the application directory.
A master directory will contain links to application directories for sourcing the index.
The master directories are named Mod and are inside any of the
the directories specified in auto_path. (This last which can
be added to using the TCLLIBPATH env var.)
The Mod subdirectory may contain the file ModIndex.tcl (note capital)
and/or any number of
links to other directories to source modIndex.tcl from. For example, assuming
the above modIndex.tcl was in the directory ~src/libx, use:
The [Mod loadmods] command is used to source ModIndex.tcl and all
the modIndex files located in the linked subdirectories.
Note that if files in mod_index use
.dll or .so ([info sharedlibextension]) then load will be used instead of source.
The actual suffix to command map is defined in the ::Mod::loadcmd array, indexed
by extension. Otherwise the default is to use source.
7. Externs
The interface or .htcl files contain the extern definitions for
commands exported from a namespace. These are usually preferred
on loading, unless an explicit Load-Code flag has been used.
If externs are not defined for a module, the source will be loaded instead.
8. Versions
Mod define a 1-1 mapping between namespaces and directories.
However, older version may delivered in parallel using a version,
which may be specified using
the () suffix. eg.
uses ::lib::x(3.1)
This will result in loading from directory "TclMod/lib/x/3.1", if it exists, otherwise
fallback to "TclMod/lib/x", etc.
Note: The actual work of loading code
and/or import commands is performed by [Mod autoimport].
Note: Weld code validation
can make use of static uses definitions (as long as you use [uses] and not [Mod uses]).