Feature Index
Similarities with XOTcl, ITcl and Java
Classes
Inner (nested) classes
Access control: "public" "protected" and "private"
Objects:
Dynamic objects
Common objects
A Tcl command for each object
Direct access to common variables
Interfaces:
As class "API's"
As weak "types"
Class inheritance:
Single class inheritance
Multiple interfaces
Inversion of control
Mixins
Member name overriding
Class constructor and destructor
Object ownership:
"new" determines the original owner
Dynamic ownership transfer
Garbage prevention:
Method-local objects deleted upon method completion
Introspection:
Commands: "my" "self" and "next"
Additional runtime commands
Object recycling and alternate constructors
Rootless native hierarchy
Dynamic revision of classes, objects, interfaces and mixins
Programmable policy settings
Implemented in pure Tcl

Feature Descriptions

The following descriptions assume that the reader is familiar with Tcl and with Java, C++, or a similar OO programming language.

Similarities with XOTcl, ITcl, and Java
In its syntax, Toe resembles ITcl; in its feature set, Toe is closer to XOTcl; with respect to design principles, Toe is modeled on Java. Toe also adopts some syntax and semantics from Java and C++, especially where no Tcl precedent exists. For example, the keywords, new, delete, public, protected, and private are all part of Java, C++ and Itcl, but are not commands or keywords in Tcl. In the Toe package, new and delete are subcommands to the command, toe. (One can also use Tcl's interp alias {} ... construct to make new and delete first-class commands, although doing so may be controversial.) As in Itcl [1], Toe uses the method and common keywords. Within class definitions, Toe also supports the subcommands, my, self, and next, modeled on their namesakes in TclOO.

Classes
The elementary components for Toe are classes, interfaces, and mixins. Of these, the main component is the class. A class is a specification for executable objects, which are created by the Toe runtime. The class defines variables and methods. For reference, a class variable corresponds to a Tcl namespace variable. A class method corresponds to a Tcl proc, and extends a Tcl proc by implicitly declaring to be within local scope all class variables, and some inherited variables. A method may also be defined such that class and inherited variables are not declared. For a given method, the method keyword may be followed by the -novars option to prevent variables being included automatically.

A class may be instantiated multiple times to create separate objects. Each object/instantiation is a namespace that contains the same methods, but holds data values that are unique to that object. The class may also be revised or redefined, but otherwise exists for the life of the application.

Inner (nested) classes
A class may define another class to be a member within itself. Access to the inner class from outside its containing class is possible, but not facilitated by Toe. The purpose of this design feature is to allow complex behavior within one class to be packaged internally as a separate class, and to provide an additional measure of isolation. As constructed, methods of the inner class have no direct access to members of the outer class.

Access control: "public" "protected" and "private"
Analogous to their use in Java and C++, the keywords, public:, protected:, and private:, and their non-modal equivalents, public, protected, and private, apply to variables and methods in class definitions. Public methods may be accessed by name from outside of the object by qualifying the object command with the method name. They may be accessed from within methods of the object either directly or by qualifying the subcommand, my. Public and protected methods of a base class may also be accessed directly from within a derived class. Private methods may only be accessed directly from within methods of the class. All methods in an object may be accessed directly from within any other method of the same object. The default access is public.

Public and protected methods and variables are inherited, although differentially. For more on the interaction of class inheritance and access to methods and variables, see below, under Inheritance.

Objects
An object of a class corresponds to a Tcl namespace and at least one namespace ensemble. Each object is created from an internal representation of the class. Dynamic objects are initialized by a "constructor" method, which is invoked internally as part of object creation. Objects may be created and deleted throughout the life of the application. The mapping between Tcl namespaces and the common and dynamic objects is managed by the Toe runtime. In general, the programmer does not need to know which namespace is associated with an object.

The common object of the inner class may be invoked from a method in its enclosing class by a command consisting of "my" plus its class name. Instantiations of an inner class may be created with toe new, and invoked within an instance of the enclosing class.

Dynamic objects
A dynamic object is one instance of a class. It is created by using the toe new classname command. If the constructor for the class requires input variables, they can be provided as extra arguments to new. All instance methods of the object are available at the time that the constructor is called.

If the class to be instantiated inherits from a base class, then an instance of the base class is created before the derived class is instantiated, and its constructor is called before the derived class' constructor is called. Common variables and methods for the class are also available at instantiation time.

Common objects
A single, common object is created for each class at the completion of parsing a class specification. The common object is populated by variables and methods that are defined with a leading common keyword, or while the common scope applies, as specified by the common: keyword. The conjugate keyword object: can be used to revert to the default scope for subsequent class member specifications.

The access specifiers, public and private, can be used with members of the common object. The protected keyword can also be used for common members, but access is converted internally to public, since class inheritance does not apply to the common object. Private methods in the common object are accessible only from other methods in the common object.

The command name for the common object of a class is the class name, either preceded by "::toe" or in the global namespace, depending on the current policy setting for command naming. The command name for the common object of an inner class is the fully qualified name of the inner class, which includes its outer class name(s), joined with the namespace separator, "::".

For example, using the global namespace:

% toe class C {
common:
  method hello {} {puts "Hello, world"}
}
# C
% C hello
# Hello, world


For reference, a class of only common members produces the analog of a Tcl namespace being used as an object. The above example corresponds to the following pure Tcl code:

namespace eval ::C {
  proc hello {} {puts "Hello, world"}
  namespace ensemble create -subcommands hello
}


The following example, with namespace scoping enabled, demonstrates access to a common public variable:

toe class C {
  common public variable tag "some tag value"
}
# C
% toe::C variable tag
some tag value

A Tcl command for each object
Objects are created with the toe new command, and deleted by the toe delete command. The return value of toe new is the object's command name. Object command names are assigned by Toe, and cannot be changed. A specific command name may appear to be intelligible, but should be treated as an opaque token. Command names for deleted objects are not reused in the same Toe session. With the scoped naming policy enabled, a "Hello, world" message might be implemented in a dynamic object and invoked as follows:

toe class Hello {
  public method hello {} { puts "Hello, world" }
}
# Hello
% set obj [toe new Hello]
# ::toe::Hello#1
% $obj hello
# Hello, world
% toe delete $obj

Direct access to common variables
In general, variables in a common object are managed by methods in the common object. Additionally, common variables may be accessed for both reading and writing from within a method of a dynamic object of the same class. Direct, read-write access is provided by the my common list command, which brings the listed variable(s) into the method's scope. Extending the above example, if we want a method in an instance of class C to change the value of the variable, tag, in the common object for class C, we might add a method like the following to class C:

toe class C {
  common private variable tag

  public method settag {s} {
    my common tag
    set tag "$s"
    return
  }
}


Interfaces
Interfaces are elementary components that specify public or protected methods, and public constants. An interface is specified by the command, toe interface. An interface, like a class, is an abstract specification. It does not provide an implementation for the methods that it specifies. It provides a way to express and enforce method names, method arguments, and access. Any class that implements an interface should implement all the methods that the interface specifies. Methods specified but not implemented will produce an error when called. In an interface, a method is specified by the access, its name and argument list. Interfaces may be used with any class -- they have no binding to a particular class. A class references an interface for implementation by naming the interface as a list value to the class option, implements:

toe interface I {...}
toe interface J {...}

toe class C implements I {...}
toe class D implements {I J} {...}

A class may also reference an interface for abstraction. When a class abstracts an interface, the named interface must be implemented by another class that inherits the abstracting class. Attempting to call the interface methods of an abstracting class without proper inheritance will generate an error. Abstraction is specified by naming the interface as a list value to the class option, abstracts:

toe interface I {...}
toe class C abstracts I {...}

An interface provides:
a) a modular abstraction of zero or more methods,
b) a requirement for method implementations in a class that implements it,
c) a convenient container in which to place API-level comments, and
d) a design element to help with establishing class purpose and relationships.

Interfaces may specify constant values with the const keyword. This keyword is only meaningful within the definition of an interface. A constant defined in an interface can be referenced by name from dynamic object methods of a class that implements the interface, using a qualifier to the subcommand, my. See below, under Multiple interfaces.

Interfaces as class "API's"
An interface can be used to encapsulate the application programmer's interface for a class. Additionally, in elaborate programming environments, such as team programming or vendor-customer solutions development, a fully documented interface may be exposed to external clients, while the implementation need not be disclosed at the same time. Consider the following example for a simple class to manage a stack of arbitrary items:

toe interface IStack {
  method push {item}
  method pop {}
  method peek {}
  method size {}
}

toe class Stack implements IStack {
  private variable stack
  method constructor {args} {set stack [list]}
public:
  method push {item} {set stack [linsert $stack 0 "$item"];return}
  method pop {} {set stack [lassign $stack item];return $item}
  method peek {} {return [lindex $stack 0]}
  method size {} {return [llength $stack]}
}

Functionally, the interface in this example would seem to add nothing to runtime behavior. Under the covers, the Toe package uses it to perform error-checking against an implementing class. If an inconsistency is detected, then a "class-compile-time" error may be reported.

Interfaces as weak "types"
The OO classes and interfaces that are described here should not be construed as user-defined types, as they are generally understood in programming languages. However, introspection may be used to obtain the names of interfaces that a class implements. From within an object method, the qualified subcommand, self interfaces, returns a list of interface names for the interfaces that the class implements. From outside the object, the object's command may be qualified by self interfaces to obtain the same list. Application code can use the list to validate whether a specific object implements a particular interface. Interface name-checking is also supported implicitly by the Toe runtime, as part of the Inversion of Control mechanism. (see below).

Class inheritance
A class can inherit both methods and variables from another class. Inherited methods, when invoked, execute in the scope of the instance in which they were defined. If a method in a derived class has the same name as a method in a base class then the derived method overrides the base method. For variables, however, an error is reported at class definition time if a variable in a derived class would replace a variable of the same name in the base class.

Control of exactly which variables and methods of a base class are inherited is provided by the access specifiers, public, protected, and private, which are described above. Methods and variables which are declared as public or protected in a base class are directly accessible in a derived class; methods, but not variables, are also accessible in cascaded derived classes.

A method in a derived class with the same name as a method in its base class, but with a different access specifier, causes the derived method to override the corresponding base class method, and to be treated with the new access. The overriding method should define the same argument list, but differences in the argument list are not enforced as part of the inheritance mechanism. Multiple definitions of a method by the same name are allowed, but only the last encountered method definition is used.

Public and protected variables of a base class are inherited in a derived class, and declared in all methods of the derived class. However, unlike methods, variables are only inherited by the immediate derived class. Variables that are declared as public or protected in ancestors of a base class are not inherited in the derived class. This is an intentional limitation, and is asserted as a feature.

Single class inheritance
A class may inherit only one other class. Multiple inheritance is not supported. A class may incorporate constants from one or more interfaces, as well as methods from one or more mixins, but such inclusions are not considered to be inheritance.

Multiple interfaces
The value associated with the implements option in a class definition is a non-null Tcl list. If multiple interfaces define the same method name, and have the same argument count, the effect is benign and of no consequence. If same-named methods in different interfaces have different argument counts, an error will result, because the corresponding class method cannot satisfy both method declarations. The argument lists are allowed to differ in one case: when the argument list for a method in the interface definition consists of the Tcl keyword, args.

If multiple interfaces define a constant by the same name, the constants are distinguished by the interface name. Constants are referenced as subcommands to my, where the subcommand is the fully qualified constant name, using array notation, as in the following example:

toe interface I {const p 1.23} ; toe interface J {const q 4.56}
# J

toe class C implements {I J} {
  method m {} {
    puts "p = [my I(p)]"
    puts "q = [my J(q)]"
  }
}
# C
% set obj [toe new C]
# ::toe::C#1
% $obj m
p = 1.23
q = 4.56


Inversion of Control
An important idiom for object-oriented frameworks is inversion of control. Firstly, a framework is defined as a collaborating set of classes, which collectively provide a resource or service to clients of the framework. In a complete and consistent framework, clients call into a framework at designated entry points, and the framework is fully implemented to respond accordingly. Such a framework might also be called a toolkit. In an incomplete framework, implementation is partial, but provision is made for a client class to couple and collaborate with the framework, in order to enable a framework's mission.

In the inversion of control idiom, a user-supplied collaborating class provides completion to an otherwise incomplete framework. In order to complete the framework, the collaborating client class must implement a specific interface that the framework requires. When a framework is completed by a collaborating and conforming client class, a framework class can safely send messages to the client class in order to fulfill the framework's functionality.

The mechanism in this package to support inversion of control has three requirements:
  1. an interface to be implemented by a framework-collaborating client class;
  2. an abstract framework class that references the interface in its definition by the abstracts option;
  3. a client class that both implements the same interface and inherits from the abstracting framework class.

It is recommended, but not necessary, to have a second interface, J, which defines the framework's public entry points, and which the abstracting framework class implements. The methods declared by interface J may then be called on an object of the derived class D, even though class D does not implement any of the methods specified by interface J.

Mixins
A "mixin" in this package is a specification, but not a class. It is a component that specifies methods and filters to be incorporated into class objects. A mixin is specified by the toe subcommand, mixin, and a class references a mixin as a list value to the class option, mixes, in the class definition line. A class may reference multiple mixins in a Tcl list. Mixin methods, like class methods, can use introspection, as well as directly reference the class variables for the mixing class.

Mixin filters specify the name of a class-implemented method that is to be bracketed with prepended and appended scripts. A prepended script can affect the return value of the method. But an appended script cannot affect the return value of the method. In the definition of a filter, the special name, "*", causes the filter to be applied to all methods of the mixing class.

If the mixing class is a base class, then the public mixed-in methods are inherited. If a class and a mixin name the same method, then the mixed-in method applies. If multiple mixins each contain a filter with the same name, and a class having a method of the same name mixes them all in, then the prepending and appending scripts are applied cumulatively, with the semantics of successive enclosure, where the filter from the first-listed mixin occurs inner-most.

Mixins are free-standing specification, and have no binding to a particular class. However, variable names that appear in the code for a filter may inadvertently access class variables in the mixing class, introducing unexpected, class-specific dependencies.

Mixins provide a mechanism to adjust an existing implementation without disrupting an otherwise stable design. Mixins also allow the inclusion of functionality that is complementary or orthogonal to a core design and implementation, such as for pre- and post-condition checking, satisfying non-functional requirements, implementing aspects, logging, or persistence.

Member name overriding
A method in a derived class with the same name as a method in a base class replaces the base class version in the derived class. However, during execution, if a method of the base class calls another method in the base class which the derived class overrides, then the base class version of the method will still be called. That is, method overriding applies in the context of a derived class, or clients of the derived class, but not in the context of the base class that incurs a method override. This is called the "local precedence" rule. If an unambiguous "call-down" from base class to derived class is desired, the preferred mechanism is to abstract an interface that specifies the method.

Class constructor and destructor
Each class has a constructor and destructor method. If these methods are not included explicitly as part of the class definition, then null methods are provided implicitly. The private methods are called by the Toe runtime, as part of creating, via new, or destroying, via delete, an instance of the class. Constructors and destructors of base classes are also called as part of instantiating or deleting, respectively, a class that inherits. In an inheritance hierarchy, the constructor of the most derived class is invoked last. An explicit constructor should always be defined with args as its argument list.

As an added feature, the constructor is also called if the object is reset, copied, or cloned, using the Toe runtime services (see below). The constructor and destructor methods are private, and should not be called by application code.

It is good programming practice to limit the use of the constructor and destructor to initializing and cleaning up class variables. In particular, a class variable that is to be used as a Tcl array variable should be initialized in the constructor.

Object ownership
An object created with the new command may be owned by another object. A dynamic object may be owned by either another dynamic object or a common object. A common object may not be owned. Ownership is managed by the Toe runtime.

Original owner
The original owner of a newly created instance is the object within which the toe new executes. If new is executed in the global namespace, then the object is originally not owned. Deleting an object using toe delete from anywhere in the application's code also removes the runtime record of ownership. Attempting to delete an object by a command name that is no longer valid produces an error.

Dynamic ownership transfer
The owner of an object may be changed by the Toe runtime subcommands, orphan, adopt and seize. orphan places an object in the unowned state; adopt changes the ownerhip status of an object from either being unowned or owned by some object to being owned by the adopting object; seize, if enabled, forces an object to become owned by the seizing object. Seizing ownership is a normally disabled feature; to enable this feature, enter: toe policy seize 1.

Garbage Prevention
In compiled languages, "garbage" refers to a portion of an application's address space for which references to the contents of that portion have been removed or lost to the application. Tcl is implemented such that garbage is not generated. However, in the context of this package, it is possible for all known references to an object to be lost or deleted, rendering the object isolated by reference from within the Toe framework. Such an object is essentially "garbage." To prevent objects becoming unusable, object ownership and object lifetime are coupled.

If an object that owns other objects is deleted, then the objects owned by the object being deleted are automatically deleted as part of the process of deleting the requested object. This is to prevent an object from persisting when only its owner knows about it. However, as with other command-creating object systems, the inverse situation remains possible. The name of an object's command may be held in a variable after the object that it references is deleted, making the name stale as a command. Because of possible object volatility, the user is encouraged to use the Tcl command, info command name, to verify as needed whether an object command name is still valid.

Owned objects may also be deleted programmatically before the requested object is deleted, thus avoiding the need for runtime garbage prevention.

Method-local objects deleted upon method completion
A feature of the new subcommand is that it recognizes the -local option. When used in the body of a method, this option causes the object created with toe new -local to be deleted automatically when program control exits the method.

Introspection
This package provides several features that supplement what is essential for OO programming, primarily to return the state of classes and objects as the software is running. The Toe runtime also supports introspection, through the toe command and subcommands, where the desired information is not specific to a class or an object.

Introspection commands: "my" "self" and "next"
Introspection and self-aware commands in the TclOO package, namely, my [2], self [3], and next [4], are implemented in this package to be consistent with, and a superset of, the TclOO offerings. (see Synopses and Examples)

Additional runtime commands
For introspection exceeding a single class or object, the Toe runtime supports toe info. To change the composition of a class, object, interface or mixin, the runtime supports toe revise. To set or review runtime policies, the runtime supports toe policy. These commands are described in detail under Synopses and elsewhere.

Object recycling and alternate constructors
A special feature of this package is a mechanism for a dynamic object to reset itself, which returns the object to its state after its constructor method is invoked. When the reset feature of the Toe runtime is invoked on an object, all internally owned objects are deleted, all class variables in the object are unset and reinitialized, all objects in the inheritance hierarchy of the object are similarly reset, and the constructor method for each object in the inheritance hierarchy is invoked. This offers several benefits over deleting a current object and replacing it with a new object of the same class:

  1. It's faster; the overhead of new and delete are avoided;
  2. Existing references to the object's command name remain valid;
  3. Any history of revisions to a specific dynamic object is preserved.

The Toe runtime also supports copying and cloning ("deep copying") an object.

  • To copy an object means to create a new instance of the class for the object, and to copy the value of the class variables from the variables in the object being copied. Base objects in an inheritance hierarchy are also copied. Any objects owned by the object being copied, or owned by objects in its inheritance hierarchy, may either remain owned by the original object or be adopted by the copied instance.
  • To clone an object means to create a new instance of an object, new instances of all objects in its inheritance hierarchy, new instances of all objects that the original object owns, and new instances of objects owned by base objects in the original object's inheritance hierarchy. In addition, object command names in any of the class variables are replaced in the cloned objects so that they properly reference newly owned objects.


Rootless native hierarchy
When a class is defined without the inherits option, and is instantiated using new, the resulting object inherits nothing. This is consistent with instantiation in C++, but differs from the treatment of classes in Java, which implicitly include a root class, named "Object."

Toe replaces what may appear to be lost by not having an implicit root object with exposed runtime functionality and extended introspection.

Dynamic revision
Methods in classes, objects, interfaces and mixins can be added or revised with the toe revise command. This includes methods in inner classes and common objects. The interfaces and mixins that a class references can also be revised, to apply to subsequent instantiations of the the class. Class variables cannot be added, removed or renamed by dynamic revision.

Programmable policies
To review or set runtime policies, Toe supports the command, toe policy name ?0|1?. With this command, the state of a runtime policy may be inspected, enabled or disabled. Policies include garbage prevention, permission to redefine classes, interfaces and mixins, and a "strict" mode, which invokes more rigorous validation when a class is defined. Policies are described further under Synopses and Styles.

Pure Tcl
This package is implemented in pure Tcl, requiring Tcl 8.5 or later. It uses only Tcl commands that are available in a safe interpreter, and should be platform-neutral.