TIP #112 Version 2.7: Ensembles are Namespaces are Commands

This is not necessarily the current version of this TIP.


TIP:112
Title:Ensembles are Namespaces are Commands
Version:$Revision: 2.7 $
Author:Donal K. Fellows <donal dot k dot fellows at man dot ac dot uk>
State:Draft
Type:Project
Tcl-Version:8.5
Vote:Pending
Created:Thursday, 10 October 2002

Abstract

This TIP proposes unifying the concept of ensembles (from [Incr Tcl]) with namespaces and commands. It also adds control of command rewriting to allow for more efficient support for object systems like Snit.

Rationale

Tcl's subcommand-style command collections (e.g. array, info, string, interp, etc.) are a very intuitive and popular way of structuring collections of related commands. However, it is quite awkward to write Tcl code that behaves that way. Users of [Incr Tcl] have access to ensembles which provide that, but it would be a very useful feature for many other uses too.

At the same time, it is becoming clear that many applications want to commonly refer to commands inside other namespaces directly (instead of through the [namespace import] mechanism) but the syntax for doing this is verbose and not as elegant as it might be.

I believe that the same solution can address these two problems in one go, and make the language stronger and more usable for it.

Furthermore, by giving the programmer control over the mapping from the ensemble subcommands to their implementing commands, we can build a simple class system on the cheap since we can, in effect, import commands from elsewhere into the ensemble. Indeed, by extending the mapping so that it allows the specification of not just the implementing command, but also some leading arguments to that command (similar to what you can do with the [interp alias] mechanism) this becomes a very powerful mechanism indeed.

Finally, a sophisticated extra capability is the addition of an unknown subcommand callback to allow the creator of the ensemble to specify a customized strategy for handling subcommands that are not recognized by the ensemble machinery. The handler itself has several possible strategies for dealing with the problem: throwing an error (with any string as the message) is one, of course, but the handler may also add new subcommands to the ensemble and ask the ensemble to have another go, or even do the subcommand execution directly for itself.

Proposed Change

I propose to add a new subcommand to the [namespace] command, ensemble, that creates and manipulates the ensemble command for a namespace. Each namespace may have any number of ensemble commands associated with it, with the default name of an ensemble command being the fully-qualified name of the namespace itself, though it will be legal to rename ensemble commands (anyone wanting to track such events should use the [trace] command.) Tcl will not create an ensemble command for any namespace by default.

The [namespace ensemble] command will have the following subcommands:

create

For creating a new ensemble for the current namespace. The command takes a list of option value pairs (as defined below) to set the ensemble up with. As stated above, the default command name is exactly the name of the namespace, but any other name may be supplied (via the -command option); if it does not start with a namespace separator, the name will be taken as being relative to the current namespace.

configure

For reading and writing the configuration of a particular ensemble. The command takes an argument specifying the name of the ensemble to configure, and then works with either no extra arguments (when it retrieves the entire ensemble configuration), one extra argument (the name of the option to retrieve), or a list of option value pairs to configure the ensemble with.

exists

This subcommand (which takes a single argument) tests whether a command (with the given name) exists and is an ensemble.

The options available for creation and configuring are:

-export

This option (if non-empty) specifies a list of ensemble subcommands that the ensemble supports. It does not need to be sorted. Each command is mapped according to the dictionary in the -map option (if a non-empty map is present and the command has a mapping) or to the correspondingly named command (which is not required to exist at the time this is specified) in the context namespace.

-map

This option (if non-empty) specifies a dictionary that maps from ensemble subcommand names to lists of arguments to substitute into the ensemble invokation in place of the ensemble command name and the subcommand name. See the -export option for the meaning of this option when that option is also non-empty. If this option is empty and the -export option is empty too, the namespace will use the exported commands of the namespace as its command set, dynamically determining them (subject to cacheing) every time the ensemble is invoked.

-prefix

This boolean option (which is on by default) controls whether unambiguous prefixes of ensemble commands are recognized as if they were the fully specified ensemble command names.

-unknown

This provides (when non-empty) a command fragment to handle the case where an ensemble subcommand is not recognized and would otherwise generate an error. It is executed by concatenating on all the arguments to the ensemble command and then evaluating the resulting script in the scope of the caller; the result of the script and any result code generated are passed directly back to the caller unless the result code is TCL_CONTINUE (as generated by the [continue] command) when instead the input command will be reparsed (which is ideal for when the ensemble's configuration has been updated by the unknown subcommand handler.) If during reparsing the ensemble command still cannot find anything to implement a subcommand, an error will be thrown (i.e. for any particular invokation of an ensemble, its unknown handler will be called at most once.)

Ensemble creation takes an extra option value pair:

-command