Version 5 of Thoughts on implementing OO in tcl

Updated 2006-03-21 19:31:36

by MS, an absolute beginner


Wish 0: Instance variables should be *regular* tcl variables, and should allow handling as such (set, lappend, trace, ...). In the same vein, instance procs should be *regular* tcl procs. In general, the OO approach should stay fully compatible with tcl. Ideally there is no new parser or compiler for OO, everything is paresd/compiled by tcl in the usual manner. Also, if somebody defines a new Tcl_Obj, the OO system can *automatically* use it for variable values without having to define extra handling commands - whatever is implemented in tcl works in OO-tcl too (up to possible name collisions, of course ...)

Wish 1: OO should not add a (significant) performance penalty: you need fast method dispatching

Wish 2: Creation and destruction of objects should be a quick operation, in order to allow/encourage the use of short lived objects. To *my* mind, this is of secondary importance; I might be *very* wrong on this though, I just have no experience on GUI programming where I imagine that issue could jump to the foreground.

Fact 1: An object is a "namespace": it gives a special meaning to variable and command names. The usual association of namespaces to classes is beyond me - even for static OO, objects of a same class give a different meaning to names.

So, it seems that it makes sense to use tcl's namespace facilities to implement objects. This is (as I see it) the unifying feature in several of the proposed pure-tcl OO approaches. However:

  • Tcl provides relatively good facilities for command inheritance, via namespace import; but it does have its problems (addressed below)
  • Tcl does not provide adequate facilities for variable inheritance (as discussed below). Variables will probably have to be *copied* at object creation time ...
  • Tcl namespaces are relatively heavyweight

Fact 2: A *user friendly* object is also a command - as evidenced in just about every OO implementation.


Issues with "namespace import"

"namespace import" is a good way to inherit methods: the method will not be recompiled by the inheritor, the bytecode is usable as is; it is relatively lightweight; it provides for a nice dynamic updating of object methods (change the code at the origin, every inheritor is updated automatically and only the first user recompiles!)

On the other hand, a method to be imported into a different namespace has to be carefully programmed to insure that the methods of the intended object are used. The only nice way I see to do that implies:

  1. the method has to receive the name of the object to which it has to apply
  2. every command within the method should be fully qualified: either it is a global command, or else a method of the object being processed, or a method of some other object determined at compile time.

So: either the (inheritable) method programmer has to be extra careful, or else the system has to provide its own proc parser for inheritable methods. That is quite a job; and I for one do not like the idea ...

If done from C: one could (almost) force a correct coding of instance procs by defining a special command-name-resolver for namespaces that are objects, so that every command reference is global.

An alternative would be to wrap the whole body in an "uplevel" command - slow as mail, the body will never be compiled. Or else, inherited procs will have to be *copied* to the new object (I haven't thought about commands written in C yet); this implies a slower object creation, and a compilation at the first call of each method.

Linking to the instance variables of the intended object can also be done using "global" on the fully qualified name (or "upvar", depending on the implementation of the OO system). "variable" is out of the question, it will link to the variables of the object where the proc was originally implemented.


Issues with variables

There is no equivalent to "namespace import" for variables at the tcl level (you can do it in C, but keep reading).

Even if there were, the semantics of tcl do not allow a similar mechanism:

  • Commands are "imported" *only* for "read access" (read execution); if you write to them ("proc", "rename", "import" again), the modification does *not* affect the original.
  • If you link variable a to variable b (at the C level), you obtain a *full* linking: the names a and b are fully equivalent. You cannot update a without changing b, you cannot trace a (the trace will be on b!), ... This cannot be solved at the variable-name-resolver level: the resolver only receives a request for an address, and *not* the intended use of that address. It cannot therefore give different addresses for (read, write, create, unset) accesses.

Therefore, variables have to be *copied* from ancestors at object creation time. This precludes a (simple, fast, ...) dynamic updating of "class variables", every variable is an instance variable.

Actually, my knowledge and imagination failed me; dynamic updating can be implemented with read traces on the objects variables ...


Category Essay | Category Object Orientation