XOTcl - Language Reference - Index

Version: 0.81a

The Extended Object Tcl (XOTcl) Language Reference contains the following parts:

Introduction

XOTcl [Neumann and Zdun 2000a] is an extension to the object-oriented scripting language OTcl [Wetherall and Lindblad 1995] which itself extends Tcl [Ousterhout 1990](Tool Command Language) with object-orientation. XOTcl extends OTcl resulting in an own shell, the xotclsh. This shell takes the commands (similiar to the tclsh) one by one from a file or the console and interpretes them using the Tcl-interpreter. For that reason all Tcl-commands remain avaiable (and are also applicable on the extension constructs).

A central property of Tcl is, that it uses strings solely for the representation of data. For that reason it offers a dynamic type system with automatic conversion. All components (e.g. written in C) once integrated in Tcl automatically fit together and the components can be reused in unpredicted situations without change. The evolving component frameworks have proven to provide a high degree of code reuse, a rapid application develpoment and an ease of use, since the application developer may concentrate on the application task solely, rather than investing efforts in fitting components together. Therefore, in certain applications scripting languages like Tcl are very useful for a fast and high-quality development of software (see [Ousterhout 1998] for more details).

Tcl is equipped with appropriate functionalities for the easy gluing of components, like dynamic typing, dynamic extensibility and read/write introspection. OTcl is a object-oriented extension to Tcl, which encourages a programming style and is composed of constructs with properties similiar to Tcl. It offers an object-orientation with encapsulation of data and operation without protection mechanisms and single and multiple inheritance. Furthermore it enables to change the relationships dynamically, offers read/write introspection, has a three level class system based on meta-classes and offers method chaining. These abilities are integrated in XOTcl with only slight changes to OTcl visible to the programmer.

The XOTcl extension aims at complexity and adaptability issues that may occur in context of large (object-oriented) software structures. In particular we added the following support:


  

Figure 1: Language Extensions of XOTcl



Object and Class System

In XOTcl every object is associated with a class over the class relationship. Classes are special objects with the purpose of managing other objects. ``Managing'' means that a class controls the creation and destruction of its instances and that it contains a repository of methods (``instprocs'') accessible for the instances. Object-specific methods are called ``procs'', instance methods are called ``instprocs''.

The instance methods common to all objects are defined in the root class Object (predefined or user-defined). Since a class is a special (managing) kind of object it is managed itself by a special class called ``meta-class'' (which manages itself). One interesting aspect of meta-classes is that by providing a constructor pre-configured classes can be derived. New user-defined meta-classes can be derived from the predefined meta-class Class in order to restrict or enhance the abilities of the classes that they manage. Therefore meta-classes can be used to instantiate large program structures, like some design patterns (see [Neumann and Zdun 1999a] for more details). The meta-class may hold the generic parts of the structures. Since a meta-class is an entity of the program, it is possible to collect these in pattern libraries for later reuse easily.

XOTcl supports single and multiple inheritance. Classes are ordered by the relationship superclass in a directed acyclic graph. The root of the class hierarchy is the class Object. A single object can be instantiated directly from this class. An inherent problem of multiple inheritance is the problem of name resolution, when for example two superclasses contain an instance method with the same name. XOTcl provides an intuitive and unambiguous approach for name resolution by defining the precedence order along a linear ``next-path'' incorporating the class and mixin hierarchies, which is modeled after CLOS. A method can invoke explicitly the shadowed methods by the predefined command next. When this command is executed a shadowed method is ``mixed into'' the execution of the current method. Method chaining without explicit naming of the intended method is very important for languages supporting a dynamic class system, because one ca not predict which classes are currently participating in the inheritance hierarchy (often necessary in inheritance models, like C++).

The usage of next in XOTcl is different to OTcl: In OTcl it is always necessary to provide the full argument list for every invocation explicitly. In XOTcl, a call of next without arguments can be used to call the shadowed methods with the same arguments (which is the most common case). When arguments should be changed for the shadowed methods, they must be provided explicitly in XOTcl as well. In the rare case that the shadowed method should receive no argument, the flag --noArgs must be used.

An important feature of all XOTcl objects is the read/write introspection. The reading introspection abilities of XOTcl are packed compactly into the info instance method which is available for objects and classes. All obtained information can be changed at run-time dynamically with immediate effect. Unlike languages with a static class concept, XOTcl supports dynamic class/superclass relationships. At any time the class graph may be changed entirely using the superclass method, or an object may change its class through the class method. This feature can be used for an implementation of a life-cycle or other intrinsic changes of object properties (in contrast to extrinsic properties e.g. modeled through roles and implemented through per-object mixins [Neumann and Zdun 1999c] ) . These changes can be achieved without loosing the object's identity, its inner state and its per-object behavior (procs and per-object mixins).

  

Figure 2: Object and Class System

Basic Functionalities

 
Objects

Initially XOTcl offers two new commands: Object and Class. They represent hooks to the features of the language. This section discusses both of them in detail and shows how they function in the context of XOTcl. Note, that even if most of this is compatible to OTcl, a few changes occur. For this reason, this section is no introduction to plain OTcl. The Object command provides acces to the Object-class, which holds the common features of all objects, and allows us to define new objects. Objects are always instances of classes, therefore, objects defined with the Object command are (initially) instances of the Object class. But since they have no user-defined type, they may be referred to as singular objects. As all other objects they may be specialzied by object-operations and -data.

The object command has the following syntax:

  Object objName ?args?

A command of this form is a short-cut for a message to the create instance method (forwarded automatically by the unknown mechanism, which is invoked every time the message dispatch system discovers an unknown message):

  Object create objName ?args?

It creates a new object of type Object with the name objName (in fact it invokes a create call on the Object-class). objName becomes a new command, which allows us to access the created object. Similiar to the Object-command it may be used like a normal Tcl-command (using sub-commands to access the object's methods). Therefore, this form of access is called object-command approach. A simple example is an object which holds the information of a kitchen. It is created by:

  Object kitchen

An object creation calls the constructor init of the object's class. The destruction of an object is handled by the destroy instance method. The general syntax of destroy is:

  objName destroy

E.g. the kitchen object is destroyed by:

  kitchen destroy

To invoke a user-defined destruction process, it is possible to overload this instance method in every class derived from object.

Data on Objects

The Object-class provides a range of operations to manage objects, including those to manipulate data-structures on the objects. They are similiar to the same-named Tcl-commands:

  objName set varname ?value?
  objName unset v1 ?v2 ... vn?

The set instance method with given value-option allows us to manipulate an object-variable's value or to create a new one, if the variable varname does not exist on the object so far. Without value-option the set-operation queries the variable and returns it's value, if the variable exists, otherwise it produces an error message. The unset-operation deletes one or optionally a set of variables from an object. For example the kitchen-object can store information on the color of the wall-paper by:

  kitchen set wallPaperColor white

Similiar to Tcl-variables the object variables are dynamical; they may be set at run-time when they are needed and unset when they become obsolete. E.g. the persons in the kitchen may be stored in an array. If there are no persons in the kitchen the array is deleted:

  # Peter enters the kitchen to cook
  kitchen set persons(cook) Peter
  ...
  # Marion enters the kitchen to take one of the seats
  kitchen set persons(seat1) Marion 
  ...
  # Both Peter and Marion leave the kitchen
  # the array is deleted by unset
  kitchen unset persons

Since XOTcl variables are interally realized through Tcl-variables they may be treated like all Tcl-variables. For that reason they have all Tcl-variable abilities, including the possibility to handle them as lists or arrays (as seen in the last example). The array command of Tcl is mapped to an XOTcl-command directly. An object-oriented call to an object of the form

  objName array option ary args

forwards its arguments to an array Tcl-command for the object´s instance variable ary. It could be used like the same-named Tcl-command, e.g. the command

  kitchen array names persons

returns all indexes currently stored in the persons-array.

Similarly Tcl´s incr command is mapped to the object system. A call with the syntax:

  objName incr varName ?value?

increments varName with the given value (or without given value with 1).

Methods on Objects

Methods in XOTcl resemble Tcl-procedures. On objects can define object-specific methods, called procs. Instance methods which are defined on classes are called instprocs. A new proc is defined using the proc instance method of the class Object:

  objName proc name args body

The arguments of the proc instance method specify the name, the arguments as a Tcl-list or the body of the new proc. All of them must be given, only one of args and body may be empty. An example proc would be a method to let persons enter the kitchen:

  kitchen proc enter {name} {
    [self] set persons($name) [clock seconds]
  }

Here the predefined self-command is used in one of three possible ways, which allow us to access useful information when working with XOTcl-methods, these are in particular:

Note, that there is a difference to the realisation of these object informations to OTcl. XOTcl uses commands in order to make XOTcl-methods compatible to Tcl-procedures and accessible via namespace-paths. OTcl uses the three variables self, class and proc, which are filled automatically with proper values by the interpreter each time a method is called. To gain compatibility a compilation option AUTOVARS is available which provides these variables additionally (if the option is defined when compiling XOTcl). The default is, that the option is turned off.

Each XOTcl-method has its own scope for definition of local variables for the executing method. In most cases when a method uses object-variables, it is likely that the programmer wants to make one or more of these variables part of the method's scope. Then the Tcl-command for variable handling, like set, lindex, array, ... work also on these variables. The instvar instance method. It links a variable to the scope os an executing method. It has the syntax:

  objName instvar v1 ?v2 ... vn?

It makes the named variables, which must be variables of the object, part of the current method's scope. A special syntax is:

 {varName aliasName}

for one of the variables. This gives the variable with the name varName the alias aliasName. This way the variables can be linked to the methods scope, even if a variable with that name already exists in the scope. Now the enter-method can be adapted slightly and a leave-method can be added, which uses Tcl's info command to check whether the named person is in the object's persons array. To demonstrate the alias-syntax this is done with the persons-array and the alias p.

  kitchen proc enter {name} {
    [self] instvar persons
    set persons($name) [clock seconds]
  }

  kitchen proc leave {name} {
    [self] instvar {persons p}
    if {[info exists p($name)]} {
      puts "$name leaves after [expr {[clock seconds]-$p($name)}] seconds" 
      unset p($name) 
    } else {
      puts "$name is not in the room"
    }
  }

Information on Objects

XOTcl offers reading and writing introspection. The reading introspection abilities are packed compactly into the info instance method which is avaiable for objects and classes (there are special info options for namespaces, per-object mixins, filters, meta-data and assertions, which are explained separatly in the following sections). The info instance method's options, from the view of an object, are summarized in the following table. They are identically to the OTcl info options on objects.

 

The object info options

objName info args method

Returns the arguments of the specified method.

objName info body method

Returns the body of the specified method.

objName info class ?classname?

Returns the name of the class of the current object, if classnamewas not specified, otherwise it returns 1 if classnamematches the object's class and 0 if not.

objName info commands ?pattern?

Returns all commands defined on the object if pattern was not specified, otherwise it returns allcommands that match the pattern.

objName info default method arg var

Returns 1 if the argument arg of the method method has a default value, otherwise 0. If it exists the dault value is stored in var.

objName info procs ?pattern?

Returns all procs defined on the object if pattern was not specified, otherwise it returns all procs that match the pattern.

objName info vars ?pattern?

Returns all variables defined on the object if patternwas not specified, otherwise it returns all variables that match the pattern.



For example on the kitchen object

  kitchen info procs

returns enter and leave as a Tcl-list since these are the procs defined on the object.

Classes

Creating Classes and deriving Instances

There are different ways to create a class in XOTcl. They have in common that they derive the new class from a meta-class. Initially the Class command provides access to the meta-class Class, which holds the features common to all classes and allows one to derive new meta-classes. The common way to create a new class is:

  Class ClassName ?args?

Similar to the object short form, this is a short form of a call to the create-instance method of the meta-class Class, which is also executed by the standard unknown-mechanism. This mechnism is always triggered when XOTcl does not know a method called on an object. Supposed that there is no method with the name ClassName, defined on the class-object of Class, XOTcl looks up the method unknown (which is found on the Class Object) and executes it. The standard unknown-mechnism of XOTcl calls create with all arguments stepping one step to the right; in the general case:

  Class create ClassName ?args?

This may also be called directly. Besides the indirection when using unknown, in most cases there is no difference in the action performed: Firstly the memory is allocated, using the alloc instance method, afterwards the constructor init is called on the creating object, which is in this case the class-object of the meta-class Class. In seldom cases the programmer may want to suppress the init-call. To do so the alloc instance method may also be called directly:

 
  Class alloc ClassName ?args?

As seen in the preceding section objects are created in the same way. The difference was, that the command Object, which accesses a class, instead of the command Class, which accesses a meta-class, was used. The user-defined classes may also be used in the same way to create new objects:

  ClassName objName ?args?

Resembling the creation of classes this creates an object objName of type ClassName using the unknown-mechanism. That means the create instance method of the class is called. If there is no other instance method defined on the class-path so far (which would mean, an user defined creation process is invoked), the create instance method of the class Object is invoked. This method is similar to the create method of the meta-class Class. It firstly calls the alloc instance method (of the Object-class), which allocates memory for the object, and makes it an instance of it's class. Afterwards a call to the constructor init is invoked.

Now we can specify the object for the kitchen by the class to which it belongs. In this case a kitchen is an instance of a room.

  Class Room
  Room kitchen

A set-call on a class creates an instance variable on the class-object. This variable is unique for all instances, therefore, it may be referred to as a class variable.

Methods in Classes

Methods in classes are called instprocs. Instprocs are reachable for the class-object and all other instances of the class. The syntax for defining an instproc is:

  ClassName instproc procname args body

It is similar to the definition of procs on objects, but uses the keyword instproc to distinguish between the methods defined on the class-object and those defined on the class. Since all rooms (in the modelled world) have ceilings, we may want to define a simple convinience instproc, which is able to set the color:

  Room instproc setCeilingColor color {
    [self] set ceilingColor $color
  }

A special instproc, the constructor init, was mentioned already. Now we are able to define such an instproc. Defined on a class it is responsible for all initialisation tasks, which needed to be performend, when constructing a new instance object of the class. The constructor of the Room can initialize a variable for the color, in which the ceiling is painted, to white as default, since this is the color of ceilings without painting.

  Room instproc init args {
    [self] setCeilingColor white
  }

After this definition, all instances derived from the Room-class have an instance variable ceilingColor. The args argument used here is a special argument in Tcl which allows us the programmer to use a list of arguments which may change its length from call to call.

Information on Classes

Resembling to objects, information on classes may be gained through the info instance method of the meta-class Class. Note that this instance method does not only support the class info options, but also the object info options, since the accessing command refers to the class-object, which itself is an object and, therefore, offers its informations. The following table summarizes the additional info options available on classes.

The class info options

ClassName info heritage ?pattern?

Returns a list of all classes in the precedence order of the class hierarchy matching pattern or of all, if pattern was not specified.

ClassName info instances ?pattern?

Returns a list of the instances of the class matching pattern or of all, if pattern was not specified.

ClassName info instargs method

Returns the arguments of the specified method.

ClassName info instbody method

Returns the body of the specified method.

ClassName info instcommands ?pattern?

Returns all commands defined on the class, if pattern was not specified, otherwise it returns all commands that match the pattern.

ClassName info subclass ?classname?

Returns a list of all subclasses of the class, if classname was not specified, otherwise it returns 1 if classname is a subclass and 0 if not.

ClassName info superclass ?classname?

Returns a list of all super-classes of the class, if classname was not specified, otherwise it returns 1 if classname is a superclass and 0 if not.



Inheritance

Besides encapsulation of operations and state in objects, a second central ability of object-orientation is inheritance. XOTcl supports single and multiple inheritance with a directed acyclic class graph. Automatically each new class created by the instance methods create and alloc of Class inherits from Object. Therefore, it is ensured that all instances of the new class have access to the common features of objects stored in the class Object.

To specify further inheritance relationships the instance methods superclass of Class is used:

  ClassName superclass classList

E.g. in the example it may be useful to derive more then one kitchen objects from the kitchen's description and a kitchen may be seen as a special room:

  Class Room
  Class Kitchen -superclass Room

Now all instances of Kitchen are able to access the operations stored in the Room- and in the Kitchen-class. Note the transition the kitchen was going through: firstly it was a singular object, then it was an object with a user-defined class, and now it is a class. This is possible (and not senseless) because of the per-object specialisation ability and the dual shape of a class, since it is at the same time object and class. Both lead to a seamless connection of the run-time properties (the object features) and their descriptive properties (the class features). It is possible to avoid the strict distinction between them, known from static typed languages, like C++, Java, etc.

Besides single inheritance, as seen, XOTcl provides also multiple inheritance. This is syntactically solved by giving the superclass instance method a list of classes instead of a single class as argument.

  Class Room
  Class 4WallsRoom -superclass Room
  Class CookingPlace
  Class Kitchen -superclass {4WallsRoom CookingPlace}

Now the kitchen class is specialised a bit more. It is a special room which has four walls and it is a cooking place. Multiple inheritance, as seen here, is as simple to apply as single inheritance. Most often when the disadvantages of multiple inheritance are discussed, the name resolution along the class graph is the biggest problem. The question is, which method is to be chosen and which path through class graph is to be taken, if more then one method of the specified name exist on the class graph.

In the example such questions would arise for an object of the Kitchen class, if two same-named method are defined on CookingPlace and 4WallsRoom or if a method of the class Object is called, which is reachable through two paths (along CookingPlace or Room). Often - e.g. in the inheritance model of C++ - the path through the graph is not clearly determined and explicit naming of the class is necessary, which means storage of non-local information in sub-classes. Or the rules are that complicated that the programmer can only determine by trial which method is found firstly. Often different compilers of one language behave differently. This makes code reuse difficult and reduces portability.


Figure 3: The example classes and the following next-path


XOTcl goes an intuitive and unambiguous way to solve this problem. It resolutes the precedence order along a ``next-path''. Firstly the class of the object is searched, which is Kitchen in example. Then the super-classes are searched in definition order, which means at first 4WallsRoom, then CookingPlace. Each branch is searched completely, before changing to the next branch. That means, Room is searched, before the CookingPlace branch is visited. At last the top of the hierarchy, the class Object, is searched.

Destruction of Classes

Classes are destroyed by the destruction of the class-object using the destroy method of the Object class. The destruction of super-classes does not destruct the sub-classes. The super-class is simply removed from the sub-classes' super-class lists. All classes have the super-class Object, if no super-class is specified. Therefore, if all super-classes are destroyed or removed, the new super-class is Object, not: no super-class. The destruction of the class of an object does neither delete the object nor leave it without class. In XOTcl a deleted class leaves it's instances with the class Object.

So all empty class- and superclass-relationships are automatically reseted to Object. Note, that this are differences to OTcl, where the destruction of an class destroys all instances and an empty super-class list remains empty.

Method Chaining

A special feature of XOTcl is the method chaining without explicit naming of the ``mix-in''-method. It allows one to mix the same-named superclass methods into the current method (modelled after CLOS). The previously described next-path is the basis for this functionality. At the point marked by a call to the next-primitive of XOTcl the next shadowed method on the next path is searched and, when it is found, it is mixed into the execution of the current method. When no method is found, the call of next returns an empty string, otherwise it returns the result of the called method. Note, that the realization through a primitive command -- similar to the self command -- is a difference to OTcl, where next is realized through an instance method of Object. The syntax is:

  next ?arguments|--noArgs?

Note, that also the usage of next in XOTcl is different to OTcl, since the next call without arguments in OTcl means per default that no arguments are passed. But most often all arguments are passed through to the shadowed method (since it will most likely have the same signature like its precessedor). When all variables should be passed through, in OTcl it is necessary for correct variable substitution to use:

  eval $self next $args

To avoid such difficulties, we made the passing of all arguments the default case; a simple

  next

performs the task of passing all arguments to the shadowed methods. These arguments are called the standard arguments. If the standard argument feature should not be used, optionally arguments can be given or the flag --noArgs could be set as sole argument, which means that the shadowed method is called with no arguments.

As an example all classes involved in the last example should get a constructor instance method, which simply sets an instance variable on the object:

  Room instproc init args {
    [self] set roomNumber 0
    next
  }    
  4WallsRoom instproc init args {
    [self] set doorPosition 0
    next
  }
  CookingPlace instproc init args {
    [self] set stoveType electric
    next
  }
  Kitchen instproc init args {
    [self] set cookName -
    next
  }

After creation an object of class Kitchen gets automatically four instance variables cookName, roomNumber, doorPosition and stoveType setted up with default values in this order (since this is the order of the classes in the next-path). Note, that the order is important, because one missing next call, in one of the init methods, means that succeeding init methods will not be executed. This mechanism functions equally on all kinds of instprocs, not only on constructors.

The constructors use the args argument, which allows us to give a list of variable length as arguments, since they may pass through arguments for constructors further up the class hierarchy.

If a proc with the searched name exists on the object it overshadows all instprocs. A next-call in a proc leads to the normal next-paths search, starting with the object's class.

Dynamic Class and Superclass Relationships

Another property of XOTcl that distinguishes it from static typed languages are dynamics of class relationships. The realization of the definition of super-classes as seen above with the superclass method suggests already, that it is not only available at the class definition time. In the above example its appended to the class definition with "-superclass" as a short syntax for method invocation at defintion time (all other avaiable methods can also be called with a preceding dash ("-") at appended to defintions).

At any time the class graph may be changed entirely using this method. Suppose the rooms and kitchens created in modelling of a house should be displayed to a screen, but it is not determined, whether the user of the system has the possiblities for graphical outputs. Two classes TextOutput and GraphicalOutput may be defined, which handle the output. Both have an instproc paint which does the painting of the virtual world on the chosen display type. The common output requirements are handled by a derived class VirtualWorldOutput which calls the paint method of the superclass using next. In static typed languages it would need more sophisticated constructs to change the output class at run-time. E.g. a delegation to another object handling the intrinsic task of the output object would be introduced solely for the purpose of configurating the output form. With a dynamic class system we can use the superclass-method to do so easily:

  Class TextOutput
  TextOutput instproc paint args {
    # do the painting ...
  }
  Class GraphicalOutput
  GraphicalOutput instproc paint args {
    # do the painting ...
  }

  # initially we use textual output
  Class VirtualWorldOutput -superclass TextOutput
  VirtualWorldOutput instproc paint args {
    # do the common computations for painting ...
    next; # and call the actual output
  }

  # users decides to change to graphical output
  VirtualWorldOutput superclass GraphicalOutput

Sometimes, such an change to new intrinsic properties should not happen for all instances of a class (or class hierarchy), but only for one specific object. Then the usage of a dynamic super-class relationship is a too coarse-grained means. A second form of such dynamics is the changing of the relationship between object and class. This means, objects can also change their class dynamically at run-time. This feature may be used to model a life-cycle or changing roles for the object, without loosing the object's identity, inner state or per-object-specializations through procs. The class instance method enables this functionality.

An example would be an agent for the virtual world. Agents may be placeholders for persons, who interactively travel the world, or programs, which act automatically. When a person decides at run-time to give a task it has performed formerly by hand to an automatic agent, the agents nature changes from interactive agent to automatic agent, but the identity and the local state (that means the parts of the task, that are already fulfilled by the person) stay the same. This is a scenario for changing class relationships, e.g.:

  Class Agent
  Class AutomaticAgent -superclass Agent
  Class InteractiveAgent -superclass Agent

  # create a new agent for a person
  InteractiveAgent agent1

  # the person does something ...
  #and decides the change to an automatic agent
  agent1 class AutomaticAgent

Meta-Classes

As seen already, a special kind of classes are meta-classes. They are classes (and like all XOTcl-classes also objects) which contain the features common to all derived classes. We have already shown the meta-class Class, which was used in the last section to create new classes.

A new meta-class can be derived from an existing meta-class, like a normal class-definition, by defining Class as super-class, e.g.:

  Class myMetaClass -superclass Class

This defines a new meta-class myMetaClass, which has all the abilities of meta-classes. That means, that the programmer is able to specify new class features or override old ones. Afterwards he may instantiate these into new classes.

This is a very powerful language feature, since it allows one to give some classes further abilities then the others (or to restrict classes). This way large programm structures, like certain design pattern parts, may be instantiated. Meta-classes hold the common abstract parts of the structures. They allow one to form libraries of such structures very easily. E.g. a new meta-class NoClassInfo can be derived from class. Afterwards we restrict the info ability of this meta-class to an error message. All derived classes, like Agent in the example are not capable of accessing the class info method:

  Class NoClassInfo -superclass Class
  # redefine info ability
  NoClassInfo instproc info args {
    return "No class info avaiable"
  }
  # derive agent class from meta-class, which
  # can not access class info
  NoClassInfo Agent

Now a call like:

  Agent info superclass

returns in the error message.

Filter

Even though object-orientation orders program structures around data, objects are characterized primarily by their behavior. Object-oriented programming style encourages the access of encapsulated data only through the methods of the object, since this enables data abstractions. A method invocation can be interpreted as a message exchange between the calling and the called object. Therefore, objects are at runtime only traceable through their message exchanges. At this point the filters, which is able to catch and manipulate all incoming and outgoing messages of an object, starts it's work.

The filter (see [Neumann and Zdun 1999a] for more details) is a novel approach to manage large program structures. It is a very general mechanism which can be used in various application areas. E.g. a very powerful programming language support for certain design patterns is easily achievable, but there are also several other domains which are covered, like tracing of program structures, self documentation at run-time, re-interpretation of the running program, etc.

A filter is a special instance method that is registered for a class C. Every time an object of class C receives a message, the filter method is invoked automatically.

Usage of Filters

All messages to objects of the filtered class must go through the filter, before they reach their destination object. A simple example would be a sole filter on the class of the object. To define such a filter two steps are necessary. Firstly an filter-instproc has to be defined, then the filter has to be registered. The filter-instproc consists of three parts which are all optional. A filter instproc has the following form:

  ClassName instproc FilterName args {
    pre-part
    next
    post-part 
  }

When a filter comes to execution at first the actions in the pre-part are processed. Afterwards the filter is free in what it does with the message. Especially it can (a) pass the message, which was perhaps modified in the pre-part, to other filters and finally to the object. It can (b) redirect it to another destination. Or it can (c) decide to handle the message on its own. The forward passing of messages is implemented through the next-primitive of XOTcl. After the filter has passed its pre-part, the actual called method is invoked through next.

Afterwards, similar to next-calls in OTcl, the execution returns to the point in the filter, where the next-call is located and resumes execution with the actions of the post-part. These may contain arbitrary statements, but especially may take the result of the actual called method (which is returned by the next-call) and modify it. The caller then receives the result of the filter instead of the result of the actual called method.

The pre- and post-part may be filled with any ordinary XOTcl-statements. The distinction between the three parts is just a naming convention for explanation purposes.

The filter uses the args argument which lets us use a list of variable length as arguments, since it must filter a lot of different calls, which may have different argument lists. Furthermore, it may pass through arguments to other filters and the preceding filters may change the argument list.

Since any instproc may be a filter, a registration of the filter is necessary, in order to tell XOTcl, which instprocs are filters on which classes. The filter instance method is able to handle this task. Similar to the XOTcl-language introduced so far, the filter registration is dynamical at run-time. By handing a list of filters the programmer can change the filters registered on a class at arbitrary times. The filter instance method has the syntax:

  ClassName filter filterList

Now a simple example should show the filter's usage. In the preceding examples we have defined several rooms. Every time a room action occurs it is likely that the graphical sub-system has to change something on the output of that particular room. Therefore, at first we need a facility to be informed every time an action on a room happens. This is quite easily done using filters:

  Class Room
  Room r1; Room r2;       # just two test objects

  Room instproc roomObservationFilter args 
    puts "now a room action begins"
    set result [next]
    puts "now a room action ends - Result: $result"
    return $result
  }

  Room filter roomObservationFilter

Now every action performed on room-objects is notified with a pre- and a post-message to the standard output stream. We return the result of the actual called method, since we don't want to change the program behavior at all. E.g. we can set an instance variable on both of the two room objects:

  r1 set name "room 1"
  r2 set name "room 2"

The output would be:

  now a room action begins
  now a room action ends - Result: room 1
  now a room action begins
  now a room action ends - Result: room 2


  

Figure 4: Cascaded Message Filtering



All classes may have more than one filter. In fact they may have a whole filter chain, where the filters are cascaded through next. The next method is responsible for the forwarding of messages to the remaining filters in the chain one by one till all pre-parts are executed. Afterwards the actual method is executed and then the post-parts come to turn. If one next-call is omitted the chain ends in this filter method. As an example for an additional filter we may register a filter, which just counts the calls to rooms.

  Room set callCounter 0  ;# set class variable
  Room instproc counterFilter args {
    [self class] instvar callCounter
    incr callCounter
    puts "the call number callCounter to a room object"
    next
  }
  Room filter {roomObservationFilter counterFilter}

Filters are invoked in registration order. The order may be changed by removing them and adding them in new order. Filters are inherited by sub-classes. E.g. in the preceding example for the next path, an OvalOffice was derived from the Room class. Without a change to the program each OvalOffice object automatically produces the same filter output as rooms.


  

Figure 5: Filter Inheritance


Filter chains can also be combined through (multiple) inheritance using the next method. When the filter chain of the object's class is passed, the filter chains of the super-classes are invoked using the same precedence order as for inheritance. Since on the sub-class there may also be a another filter chain, without sophisticated computing in the pre- and post-parts one can produce easily a powerful tracing facility. E.g. if we want to distinguish an OvalOffice from other rooms we may want to add a filter solely for rooms of the type OvalOffice:

  Class OvalOffice -superclass Room
  OvalOffice o1;  # test object
  OvalOffice instproc ovalOfficeObservationFilter args {
    puts "actions in an oval office"
    next
  }
  OvalOffice filter ovalOfficeObservationFilter

A simple call to the o1 object, like:

  o1 set location "Washington"

produces the following output:

  actions in an oval office
  now a room action begins
  the call number 3 to a room object
  now a room action ends - Result: Washington

As seen already filter registrations can be added dynamically at runtime. But they may also be removed. Perhaps the counting on rooms should stop after a while, then a simple call of the filter method is sufficient:

  Room filter roomObservationFilter

Introspection of Filters

Since filters are normal XOTcl instprocs they can access all XOTcl introspection abilities introduced so far. In instprocs all recent information is accessible within their scope. But the filter is a mechanism, which covers more then this sole scope. The meaningful usage of its meta-programming abilities often requires to go further and to get information from the caller's and the callee's scope (e.g for delegation decisions in the filter). Therefore, we introduced rich introspection abilities for the filter.

The additional Introspection Mechanisms for Filters

objName info calledproc

Returns the name of the proc which was invoked in the original call.

objName info callingclass

Returns the name of the class from which the filtered call was invoked (if one exists, otherwise an empty string).

objName info callingproc

Returns the name of the proc from which the filtered call was invoked (if one exists, otherwise an empty string).

objName info callingobject

Returns the name of the object from which the filtered call was invoked (if one exists, otherwise an empty string).

objName info regclass

Returns the name of the class on which the filter is registered. Since the filter may be registered on other classes then the class on which it is defined, this may vary from self class.



Note, that three options with the prefix calling represent the values of self, self proc, and self class in the scope where the original call was invoked. In the following section we will show a simple program in which all of the info-options have different values, after we have discussed the similar looking trace program. In order to gain information about the currently registered filters on a certain class, the class info option filters may be queried. It returns a list of the currently registered filters:

  ClassName info filter


Examples



A simple Trace Program

The trace example primarily demonstrates the inheritance of filter chains. Since all classes inherit from Object, a filter on this class is applied on all messages to objects. The Trace object encapsulates methods for managing the tracing:

  Object Trace
  Trace set traceStream stdout

  Trace proc openTraceFile name {
    set [self]::traceStream [open $name w]
  }

  Trace proc closeTraceFile {} {
    close $Trace::traceStream
    set [self]::traceStream stdout
  }

  Trace proc puts line {
    ::puts $Trace::traceStream $line
  }

  Trace proc add classname {
    $classname filter [concat [$classname info filter] traceFilter]
  }

First we define the object and set a variable for the stream to which we send the trace outputs (here: stdout). With a method for opening and a method for closing a file we can redirect the trace stream to a file. puts is helper method for the filter to print an output to the selected output stream. In add the traceFilter is appended to the existing filters of a specified class. The actual filter method (see below) displays the calls and exits of methods with an according message. The calls are supplied with the arguments, the exit traces contain the result values. We have to avoid the tracing of the trace methods explicitly.

  Object instproc traceFilter args {
    # don't trace the Trace object
    if {[self] == "::Trace"} {return [next]}
    ::set context "[[self] info callingclass]->[[self] info callingproc]"
    ::set method [[self] info calledproc]
    switch -- $method {
      proc -
      instproc {::set dargs [list [lindex $args 0] [lindex $args 1] ...] }
      default  {::set dargs $args }
    }
    Trace::puts "CALL $context>  [self]->$method $dargs"
    ::set result [next]
    Trace::puts "EXIT $context>  [self]->$method ($result)"
    return $result
  }

As trace message we write the callee´s context (class and proc), the invoked method (using calledproc), and the given arguments. In the switch statement we avoid to print whole method bodies.

With

  Trace add Room

messages to all rooms, including all instances of Room´s sub-classes, are surrounded with a CALL and an EXIT output. With

  Trace add Object

messages to all objects in an XOTcl environment are surrounded with a CALL and an EXIT output. In general, it is possible to restrict the trace to instances of certain classes, or to produce trace output for only certain methods. This requires registration methods and a more sophisticated implementation of the filter method.


Information Example

Now we discuss a simple example that shows that all filter introspection options may have different values:

  Class InfoTrace
  InfoTrace instproc infoTraceFilter args { 
    puts "SELF:                [self]"
    puts "SELF PROC:           [self proc]"
    puts "SELF CLASS:          [self class]"
    puts "INFO CLASS:          [[self] info class]"
    puts "CALLED PROC:         [[self] info calledproc]"
    puts "CALLING PROC:        [[self] info callingproc]"
    puts "CALLING OBJECT:      [[self] info callingobject]"
    puts "CALLING CLASS:       [[self] info callingclass]"
    puts "REGISTRATION CLASS:  [[self] info regclass]"
    [self] next
  }

  Class CallingObjectsClass
  CallingObjectsClass callingObject
  Class FilterRegClass -superclass InfoTrace
  Class FilteredObjectsClass -superclass FilterRegClass 
  FilteredObjectsClass  filteredObject 
  CallingObjectsClass instproc callingProc  
  filteredObject set someVar 0
         
  FilterRegClass filter add infoTraceFilter

The invocation of callingObject callingProc produces the following output:

  SELF:                ::filteredObject
  SELF PROC:           infoTraceFilter
  SELF CLASS:          ::InfoTrace
  INFO CLASS:          ::FilteredObjectsClass
  CALLED PROC:         set
  CALLING PROC:        callingProc
  CALLING OBJECT:      ::callingObject
  CALLING CLASS:       ::CallingObjectsClass
  REGISTRATION CLASS:  ::FilterRegClass  

The filter reports for self the value filteredObject, since this is the object on which the set call is invoked; infoTraceFilter is the method of the filter, and therefore the actual proc, while the actual class is InfoTrace, the filter's class. The class of the actual object is FilteredObjectsClass.

The called procedure is set. While the program stays in a XOTcl-instproc all calling-info-options are set, the calling procedure is callingProc, the calling class is the class, where the method is defined (namely CallingObjectsClass), and the object from which the call invoked is callingObject.

Since the filter's registration class differs from the class, where it is defined, the corresponding information is still missing (in this example FilterRegClass).

Per-Object Mixins

Per-object mixins (see [Neumann and Zdun 1999c] for more details) are a novel approach of XOTcl to handle complex data-structures dynamically. It resembles the filter presented in the preceding section. While the filters work on classes and whole hierarchies, the per-object mixin is applied on a single object. Therefore, it is a language construct mainly working on the object-level, while filters work on the level of classes and hierarchies of classes. The per-object mixin is a class which is mixed into the precedence order of an object directly before the object's class itself is searched. All methods which are mixed into the execution of the current method, by method chaining or through a per-object mixin, are called mixin methods.

Supplemental Classes

Per-object mix-ins cover a problem which is not solvable elegantly just by the method chaining, introduced so far. To bring in an addition to a class, the normal XOTcl way is to define a mixin and chain the methods through next, e.g.:

  Class Basic
  Basic instproc someProc  {
    # do the basic computations
  }
  Class Addition
  Addition instproc someProc {
    # do the additional computations
    [self] next
  }

In order to mix-in the additional functionality of the supplemental class Addition a new helper class (sometimes called intersection class) has to be defined, like:

Basic+Addition -superclass Addition Basic

This is even applicable in a dynamical manner, every object of the class Basic may be changed to class Basic+Addition at arbitrary times, e.g.:

  Basic+Addition basicObj
  ...
  basicObj class Basic+Addition

Now consider a situation with two addition classes. Then following set of classes has to be defined to cover all possible combinations:

  Class Basic
  Class Addition1
  Class Addition2
  Class Basic+Addition1 -superclass Addition1 Basic
  Class Basic+Addition2 -superclass Addition2 Basic
  Class Basic+Addition1+Addition2 -superclass Addition2 Addition1 Basic

The number of necessary helper classes rises exponential. For n additions, 2n-1(or their permutations if order matters) artificially constructed helper-classes are needed to provide all combinations of additional mix-in functionality. Furthermore it is possible that the number of additions is unlimited, since the additions may produce other additions as side-effects. This demonstrates clearly that the sub-class mechanism provides only a poor mechanism for mix-in of orthogonal functionality. Therefore we provide an extension in the form of object mixin classes, which are added in front of the search precedence of classes.

Usage of Per-Object Mixins

The mix-ins methods extend the next-path of shadowed methods. Therefore, per-object mix-in methods use the next-primitive to access the next shadowed method. Consider the following example:

  Class Agent
  Agent instproc move {x y} { 
    # do the movement
  }
  Class InteractiveAgent -superclass Agent
  # Addition-Classes
  Class MovementLog
  MovementLog instproc move {x y} { 
    # movement logging
    next
  }
  Class MovementTest
  MovementTest instproc move {x y} {
    # movement testing
    next
  }

An agent class is defined, which allows agents to move around. Some of the agents may need logging of the movements, some need a testing of the movements, and some both (perhaps only for a while). These functionalities are achieved through the additional classes, which we will apply through per-object mixins.

Before we can use the per-object mix-ins on a particular object, we must register the mixins on it with the mixin instance method. It has the syntax:

  objName mixin mixinList

For example we may create two interactive agents, where one is logged and one is tested:

  InteractiveAgent i1; InteractiveAgent i2
  i1 mixin MovementLog
  i2 mixin MovementTest

At arbitrary times the mixins can be changed dynamically. For example i2's movements can also be logged:

  i2 mixin MovementTest MovementLog


  

Figure 6: Per-Object Mix-ins: Next-Path for the Example



The mixin option of the info instance method allows us to introspect the per-object mix-ins. It has the syntax:

  objName info mixins ?class?

It returns the list of all mix-ins of the object, if class is not specified, otherwise it returns 1, if class is a mixin of the object, or 0 if not.

Class Nesting and Dynamic Object Aggregations

Most object-oriented analysis and design methods are based on the concepts of generalization and aggregation. Generalization is achieved through class hierarchies and inheritance, while static aggregation is provided through embedding. Since version 8.0 Tcl offers a namespace concept which can be used as a mechanism to provide dynamic aggregations.

A namespace provides an encapsulation of variable and procedure names in order to prevent unwanted name collisions with other system components. Each namespace has a unique identifier which becomes part of the fully qualified variable and procedure names. Namespaces are therefore already object-based in the terminology of Wegner. Otcl is object-oriented since it offers classes and class inheritance. Its objects are also namespaces, but an object is more than only a namespace. Therefore, two incompatible namespace concepts have existed in OTcl in parallel.

Extended OTcl combines the namespace concept of Tcl with the object concept of OTcl. Every object and every class in XOTcl is implemented as a separate Tcl namespace. The biggest benefit of this design decision aside from performance advantages is the ability to aggregate objects and nest classes. Contrary in OTcl every object has a global identifier. Through the introspection abilities of namespaces nested classes are also traceable at runtime and can be changed dynamically. In XOTcl objects are allowed to contain nested objects, which are dynamically changeable aggregates of the containing object.



Nested Classes

The notation for nested classes follows the syntax of Tcl namespaces by using ``::'' as a delimiter. For example the description of a oval carpet and a desk can nest inside of the OvalOffice-class:

  Class OvalOffice
  # general carpet
  Class Carpet
  Class OvalOffice::Desk
  # special oval carpet - no name collision
  Class OvalOffice::Carpet -superclass ::Carpet

Nested classes can be used exactly like ordinary classes, a user can sub-class it, derive instances, etc. The information about the nesting structure of classes is available through the info instance method:

  ClassName info classchildren
  ClassName info classparent

The classchildren option returns a list of children, if one or more exist, otherwise it returns an empty string. classparent results in the name of the parent class, if the class is nested. Since nested classes are realized through namespaces, all functionality offered by Tcl's namespace command is usable from XOTcl as well.

Dynamic Object Aggregations

The nested classes only provide an aggregation of the descripitive not of the runtime properties of an object. We have pointed out the difference of object and class in XOTcl. Because of the splitting of a class into class and class-object it is possible to give each object its own namespace. The internal implementation of objects enable them to contain nested objects, which are aggregates of the containing object. In XOTcl these can be changed dynamically and introspected through the language support of dynamic object aggregations [Neumann and Zdun 2000b]. Suppose an object of the class Agent should aggregate some property objects of an agent, such as head and body:

  ClassAgent
  Agent myAgent

  Class Agent::Head
  Class Agent::Body

  Agent::Head ::myAgent::myHead
  Agent::Body ::myAgent::myBody

Now the objects myHead and myBody are part of the myAgent object and they are accessible through a qualification using ``::'' (or through Tcl's namespace command). But in the common case they will be accessed, as introduced so far: the explicit full qualification is not necessary when such variables are being accessed from within XOTcl methods, since the object changes to its namespace.

The information about the part-of relationship of objects can be obtained exactly the same way as for classes through the info method interface:

  objName info children
  objName info parent

Short Form for Object Aggregation and Class Nesting

The self command returns fully qualified names. So all usages of self automatically refer to the correctly qualified namespace. For the ease of use in procs (and instprocs) we have introduced a new syntax expressing the aggregation directly. That avoids long qualified names:

  objName ClassName aggregatedObj

This creates a new object aggregatedObj of the type ClassName aggregated on the object objName. Similarly this is also allowed on classes:

  className MetaClassName nestedClass

This creates a new class nestedClass of the type MetaClassName nested in the Class ClassName.

Relationship between Class Nesting and Object Aggregation

The classes Head and Body are children of the Agent class. It is likely that all agents, interactive or not, have properties for head and body. This implies a static or predetermined relationship between class nesting and object aggregation. Such predeterminations do not exist in XOTcl, but are simply build, when specifying the relationship in the constructor, e.g.:

  Agent instproc init args {
    [self] ::Agent::Head myHead
    [self] ::Agent::Body myBody
  }

Now all agents derived from the class have the two property objects aggregated after creation. But still they are changeable in a dynamical manner, e.g. with:

  Agent myAgent
  myAgent::myHead destroy

The agent turns into a headless agent. In companion of the introspection mechanisms such constructions could be very useful. Suppose, that in the virtual world the agents heads may be slashed from their bodies. The graphical system simply needs to ask with info children on the agent's object, whether it has a head or not and can choose the appropriate graphical representation.

Note, that the not existing relationship means a great deal of freedom and dynamics, which goes together with the ideas behind OTcl, e.g. like the renunciation of protection mechanisms. This policy in programming language design means, on the one hand, ease of programming and more expressiveness, but, on the other hand, it contains no protection against bad software architectures or programming style. We believe that no such mechanisms could hinder the programmer to do silly things, so our policy was, to give the programmer rather more powerful constructs then to make decisions in his place.

Copy/Move

Often an object has to be copied/moved. This is a very useful functionality when XOTcl should be used as a prototyping language. The XOTcl method move provides this functionality. Another common behavior is implemented by the copy method which clones the actual object to a destination object. The two methods have the syntax:
 objName move destination 

 objName copy destination

Copy and move operations work with all object/class information, i.e., information on filters, per-object mixins, parameters, etc. are automatically copied. Copy and move are integrated with class nesting and object aggregations. All copy/move operations are deep copy operations: all nested objects/classes are automatically copied/moved, too. E.g.\ if we want to reuse an imperial march object of star wars for star wars 2, we can just copy the object:

starWars::imperialMarch copy starWars2::imperialMarch

Assertions

In order to improve reliability and self documentation we added assertions to XOTcl. The implemented assertions are modeled after the ``design by contract'' concept of Bertrand Meyer. In XOTcl assertions can be specified in form of formal and informal pre- and post-conditions for each method. The conditions are defined as a list of and-combined constraints. The formal conditions have the form of normal Tcl conditions, while the informal conditions are defined as comments (specified with a starting ``#''). The lists containing the pre- and post-conditions are appended to the method definition (see example below).

Since XOTcl offers per-object specialization it is desirable to specify conditions within objects as well (this is different to the concept of Meyer). Furthermore there may be conditions which must be valid for the whole class or object at any visible state (that means in every pre- and post-condition). These are called invariants and may be defined with following syntax for class invariants:

  ClassName instinvar invariantList

or for objects invariants:

  objName invar invariantList

Logically all invariants are appended to the pre- and post-conditions with a logical ``and''. All assertions can be introspected.

Since assertions are contracts they need not to be tested if one can be sure that the contracts are fulfilled by the partners. But for example when a component has changed or a new one is developed the assertions could be checked on demand. For this purpose the check method can be used either to test the pre- or the post-conditions. The syntax is:

  objName check ?all? ?instinvar? ?invar? ?pre? ?post?

Per default all options are turned off. check all turns all assertion options for an object on, an arbitrary list (maybe empty) can be used for the selection of certain options. Assertion options are introspected by the info check option. The following class is equipped with assertions:

  Class Sensor -parameter {{value 1}}
  Sensor instinvar {
    {[regexp {^[0-9]$} [[self] value]] == 1}
  }
  Sensor instproc incrValue {} {
    incr [self]::value
  } {
    {# pre-condition:} 
    {[[self] value] > 0}
  } {
    {# post-condition:} 
    {[[self] value] > 1}
  }

The parameter instance method defines an instance variable value with value 1. The invariant expresses the condition (using the Tcl command regexp), that the value must be a single decimal digit. The method definition expresses the formal contract between the class and its clients that the method incrValue only gets input-states in which the value of the variable value is positive. If this contract is fulfilled by the client, the class commits itself to supply a post-condition where the variable's value is larger than 1. The formal conditions are ordinary Tcl conditions. If checking is turned on for sensor s:

s check all

the pre-conditions and invariants are tested at the beginning and the post-condition and invariants are tested at the end of the method execution automatically. A broken assertion, like calling incrValue 9 times (would break the invariant of being a single digit) results in an error message.

Meta-Data

To enhance the understandability and the consistency between documentation and program it is useful to have a facility to make the documentation a part of the program. There are several kinds of meta-data which are interesting for a class, e.g. the author, a description, the version, etc.

In XOTcl meta-data can be provided as atomic or structured values (like lists or object names), and can be added or removed at any time. Meta-data is inherited such that meta-data defined on a class can be propagated to all instances. Syntactically, meta-data can be specified through the metadata method with its options add and remove. Other arguments for the metadata method are interpreted as meta-data values, which may be set (with given argument) or queried. Introspection of meta-data is implemented through the info method. Below is an example for defining meta-data for a class:

  Object metadata add description version
  Object metadata description "This is the object class. It realizes all common object behavior."
  Object metadata version "1.0"

Since the meta-data is inherited, all objects get the ability to store information on description and version. For example the agent a1 may store such values:

  Class Agent
  Agent a1
  a1 metadata description "My testing agent"
  a1 metadata version "0.1"

Every class and object can store additional meta-data for its own purposes, which are also inherited by all sub-classes (if they are defined on a class). E.g. all agents can store information about the host on which they have been created and the testing agent a1 can store information about the locations it had tested already.

  a1 metadata add homeURL
  a1 metadata homeURL "http://nestroy.wi-inf.uni-essen.de/"
  a1 metadata add testedLocations
  a1 metadata testedLocations "http://nestroy.wi-inf.uni-essen.de/    
                               http://www.uni-essen.de/"

After a while the testing agent may have performed all desired tests, so he may decide to stop the testing activity. Therefore, he can turn into another kind of agent and the testing information can be removed:

  a1 metadata remove testedLocations

Introspection of meta-data is implemented through the info method. The metadata-option informs about the meta-data available on an object:

 objName info metadata

All meta-data that are defined on the object and those that are inherited and used are enlisted. The inherited options which are not set yet are not stated.

All meta-data may be queried simply by usage of the metadata method without an argument, e.g.:

  Object metadata version

This will produce the result ``1.0''.

Meta-data resembles normal instance variables. Besides the special features, like inheritance, meta-data could be expressed through instance variables solely. But especially in distributed environments, it is important to have such a facility, because the common place and the introspection mechanisms allow different people and, in XOTcl's case, even other programs, to gain the meta-data without searching for them. Since this is not only a naming convention, but a language construct, the interpreter results in an error if the meta-data is used falsely.

Additional Functionalities

Abstract Classes

In XOTcl a class is defined abstract if at least one method of this class is abstract. The instance method abstract defines an abstract method and specifies its interface. Direct calls to abstract methods produce an error message. E.g. a Storage-class provides an abstract interface for access to different storage forms:

  Class Storage
  Storage abstract instproc open  {name}       
  Storage abstract instproc store {key value}
  Storage abstract instproc list  {}         
  Storage abstract instproc fetch key        
  Storage abstract instproc close {}         
  Storage abstract instproc delete {k} 

All kinds of storage have to implement every method from the interface. E.g. a GNU Database Access, a relational database access, and several other storage forms may be derived by sub-classing (therefore, all conform to the same storage access interface).

Parameter

Classes may be equipped with parameter definitions which are automatically created for the convenient setting and querying of instance variables. Parameters may have a default value, e.g.:

  Class Car -parameter {
    owner
    {doors 4}
  }

Each instance of class Car gets two instance variables defined. owner has no default value, and doors defaults to 4. E.g. the following defines a new person object with the two paramters set:

  Car mercedes

Additionally the parameter method automatically creates a new getter/setter instance method for each parameter -- same named to the parameter, which queries the parameter if it no argument is given or sets the parameter if with an given argument. E.g. a car with only two doors can be created by:

  Car porsche -doors 2

The owner of thefirst car is set by:

  mercedes owner Marion

and the doors of the first car can be queried (and printed to the screen) by:

  puts "The mercedes got [mercedes doors] doors and is owned by [mercedes owner]"

parameter are inherited by subclasses. The class Class::Parameters contains the behavior how default values are stored ...

Checking Commands for being Objects, Classes, or Meta-Classes

Since XOTcl is a hybrid language containing several Tcl commands, sometimes its necessary for applications to distinguish between Tcl commands and object commands for XOTcl. method of the Object class looks up an objName and returns 1 if it is an object and 0 if not:

 anyXOTclObject isobject objName

If one can be sure that a command represents an object, it might be unsure if the command is only an object or also class or even meta-class. The two instance methods isClass and isMetaClass check in the same manner, whether a class or meta-class is given (since ever XOTcl class is an object, they also return 0, when objName is not an XOTcl object).

anyXOTclObject isclass objName
anyXOTclObject ismetaclass objName

Exit Handler

A task for a programming language, sometimes of similar importance as object creation, is the object destruction. XOTcl ensures that all objects are destroyed and their destructors are invoked when XOTcl applications terminate. For that reason objects and classes are destroyed in the order objects, classes, meta-classes. Sometimes further destruction order is of importance. For these cases, the XOTcl language provides an exit handler, which is a user-defined proc, which invokes user-defined exit handling just before the destruction of objects, classes, meta-classes is invoked. E.g. the exit handler lets the user specify objects which have to be destroyed before all other objects. There are three object-specific proc of the Object class pre-defined, which let us specify an exit handler conviniently.

   Object setExitHandler body
   Object getExitHandler
   Object unsetExitHandler

setExitHandler lets us specify a proc body that actually contains the user-defined exit handling. E.g.


   Object setExitHandler {
     aObj destroy
     puts "existing"
   }

destroys the object aObj before all other objects and prints the message existing to the screen. With getExitHandler the exit handler can be introspected. E.g. if we just want to append the destruction of object bObj to an exisiting exit handler, we use getExitHandler:


   Object setExitHandler "[Object getExitHandler]; bObj destroy"

unsetExitHandler deletetes the exit handler (and resets it to "").

   Object proc getExitHandler {} {
     if {[info exists [self]::__exitHandler]} {
       return [[self] set __exitHandler]
     } else {
       return ""
     }
   }

   Object proc setExitHandler body {
     return [[self] set __exitHandler $body]
   }

   Object proc unsetExitHandler {} {
     [self] unset __exitHandler
   }

Automatic Name Creation

The XOTCL autoname instance method provides an simple way to take the task of automatically creating names out of the responsibility of the programmer. The example below show how to create on each invocation of method new an agent with a fresh name (prefixed with agent):

   Agent proc new args {
      eval [self] [[self] autoname agent] $args
   }

References

[Neumann and Zdun 1999a] G. Neumann and U. Zdun. Filters as a language support for design patterns in object-oriented scripting languages. In Proceedings of COOTS'99, 5th Conference on Object-Oriented Technologies and Systems, San Diego, May 1999.

[Neumann and Zdun 1999b] G. Neumann and U. Zdun. Implementing object-specific design patterns using per-object mixins. In Proc. of NOSA`99, Second Nordic Workshop on Software Architecture, Ronneby, Sweden, August 1999.

[Neumann and Zdun 1999c] G. Neumann and U. Zdun. Enhancing object-based system composition through per-object mixins. In Proceedings of Asia-Pacific Software Engineering Conference (APSEC), Takamatsu, Japan, December 1999.

[Neumann and Zdun 2000a] G. Neumann and U. Zdun. XOTCL, an object-oriented scripting language. In Proceedings of Tcl2k: The 7th USENIX Tcl/Tk Conference, Austin, Texas, February 2000.

[Neumann and Zdun 2000b] G. Neumann and U. Zdun. Towards the Usage of Dynamic Object Aggregations as a Form of Composition In: Proceedings of Symposium of Applied Computing (SAC'00), Como, Italy, Mar 19-21, 2000.

[Ousterhout 1990] J. K. Ousterhout. Tcl: An embeddable command language. In Proc. of the 1990 Winter USENIX Conference, January 1990.

[Ousterhout 1998] J. K. Ousterhout. Scripting: Higher Level Programming for the 21st Century, IEEE Computer 31(3), March 1998.

[Wetherall and Lindblad 1995] D. Wetherall and C. J. Lindblad. Extending Tcl for Dynamic Object-Oriented Programming. Proc. of the Tcl/Tk Workshop '95, July 1995.