Mod /
Uses
Search:  


1.  Uses

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:

  1. Command name collisions
  2. 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.

   namespace eval ::myns {
      uses   ::lib::x^   ::lib::y^
      subcmd1 ...
      subcmd2 ...
      subcmd3 ...
   }

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.

    uses NSOPT NSOPT NSOPT ...

The general form of NSOPT is:

    SourceNs?@TargetNs??Flags??(1.0)?

Here is an example using [uses]:

namespace eval ::lib::x {
    Mod export 
    proc foo1 {n} { return $n }
}

namespace eval ::lib::y {
   proc foo2 {n} { return $n }
}

namespace eval ::myprog {
    uses ::lib::x  ::lib::y^

    proc bar {n} {
        x foo1 $n;  # auto-imports ::lib::x
        foo2 $n;     # auto-imports ::lib::y::foo2
    } 
}

myproc::bar 0

The invocation of x results in it's autoimport. Similarly with the x ensemble or module-command.

Note that [uses] differs from [namespace import ::lib::x ::lib::x::*] in that:

  1. individual commands are imported-on-demand.
  2. a command is imported if and only if it is called.

It should also be noted that a namespace name willout leading :: will be treated as relative to the current namespace.

Also, when using Mod an implicit uses is defined for the Tcl/Tk builtin commands.

3.  Targets

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.

namespace eval ::myns::sub {
  uses    ::lib::x@::   ::lib::y@::^ 
}

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

namespace eval ::myns::sub {
  uses   =@::^   ::lib::x  ::lib::y   ::lib::z
  uses   ::lib::x@::^  ::lib::y@::^   ::lib::z@::^
}

Mod may be used with autoimport disabled with:

set ::Mod::unknowns {}

4.  Precedence

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]:

CHDESCRIPTION
^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:

  mkdir -p ~/lib/Mods
  cd ~/lib/Mods
  ln -s ~/src/libx .
  export TCLLIBPATH=~/lib
  tclsh ...

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]).

© 2008 Peter MacDonald

Page last modified on February 19, 2008, at 09:15 PM