Basic Ideas

My first experiences with OO extensions in Tcl/Tk was Itcl which I used intensively on programming my CMS One Hand Content. This extension worked mostly as expected – with a few pitfalls and one thing I found annoying: options were mapped to internal variables of the objects. More than once I ran in danger of name collision inside method definitions.

Then, I found Snit and really enjoyed it. Especially, options are mapped to key/value pairs of an array. No more danger of name collision! — Instead of heritage, components are installed where methods and options can be delegated to: really great! — But, I found the hint that performance disappoints if there are many once-used local objects. But that was exactly what I wanted in my current project on computer-generated cartoons.

So, I made obj — just another OO system. It does not seamlessly fit into Tk's object approach, and it is far from being complete. But it is minimalistic, and it is (at least intended to be) quite fast. It is made as follows:

Location

The basic procedures are located in namespace ::obj. An object class resides in an own namespace below basic procedures — ::obj::class::classname — where its methods are located as well as the array data with the individual data for the instances.

A method is just a procedure where the instance name is first argument. The first argument variable is fixed to the name self. The procedure ::obj::method automates that.

Instance creation

Besides a few pre-defined prcedures and methods, here resides the basic procedure _root-object_ which is the master procedure for all method calls.

An instance is created as follows:

  1. The procedure _root-object_ is referenced with the Tcl expression namespace import.
  2. Then, this newly imported procedure is renamed to something like ::obj::inst::1 — which is the object's tag. It can always be referenced by the Tcl command ::info level 0.
  3. When the object is invoked with ::obj::inst::1 method1 ..., then the referenced procedure _root-object_ calls method1 ::obj::inst::1 ... inside its namespace.

The consequences are: 

No heritage

Obj does not provide class heritage as used by Itcl, but instead component delegation as used by Snit, as follows:

Besides options, an instance $o can have private data with the statement:

$o private key val

If val is the name of an instance, then it can be treated as component with the statement:

$o component key method1 ...

Internal values

Differently to other object systems, no mapping to Tcl variables, instead instance-internal values are accessible only by the methods configure, cget, private, and common, and the abbreviation procedures my and our.

Differently to Itcl, methods are realized as procedures, but not mapped to procedures. Inside method definitions, own methods must always invoked via $self method1 .... The advantage is: no confusion with regular procedures.

Delegation

If you wish that every instance of class dog has a private component tail, then write the appropriate constructor: 

% ::obj::constructor dog {} {
  $self private tail [new tail]
}
constructor dog
%

If you wish that every method call wag on an instance of dog is done by its component tail, then delegate it as follows:

% ::obj::delegate method wag dog tail
class dog delegates method wag to component tail.
%

You can do the same with options, e.g. -length. — For more details, see the documentation.

Interoperability

If you work with inherited objects of other object systems, e. g. Snit, or Itcl, then you can use their instances as components of obj instances. They live peacefully side-by-side. As delegation of methods and options just triggers an appropriate method definition, delegating obj things to Itcl components works as well as to own objects!

© Wolf-Dieter Busch | Home | Sitemap | Urheber | A-Z