Ensemble objects

Synopsis

A (mostly) better alternative to namespace ensemble:

oo::object create stash 
oo::objdefine stash {
    variable Stash
    method set {name val} {
        set Stash($name) $val
    }
    method get {name} {
        return $Stash($name)
    }
}

A few things are noteworthy:

  • we didn't define a class! TclOO lets us define oo::objdefine methods directly on any object.
  • methods don't get in the way of command resolution inside the object: we can call set without worrying that a method set exists. To call other commands within the ensemble, just use my
  • we have no control over the object's namespace. This is mildly dissatisfying compared to ensembles, but self namespace is better than a hardcoded reference -- it makes each method copy&paste-portable to other objects

Rationale

Historically, namespace ensembles have been plagued with one wart: command resolution starts in the ensemble's namespace. Thus, subcommands with names like set are problematic:

namespace eval stash {
    proc set {name val} {
        variable Stash
        set Stash($name) $val
    }
    proc get {name} {
        variable Stash
        return $Stash($name)
    }
    namespace export *
    namespace ensemble create
}

This example will fail, because stash set accidentaly calls itself! This can be worked around by using ::set, but such changes are ugly. And not just cosmetically: try extending an existing ensemble with a set method, or gracefully using namespace path.

TclOO provides a neat solution to this: simply use an object.

Anonymous comment 2016-05-02: The impact of this wart can be reduced somewhat with -map:

    ...
    proc _set {name val} {
    ...
    namespace ensemble create -map {set _set get get}

WHD: Another way to convenient create an ensemble is to use a snit::type as a singleton. It's a namespace ensemble under the covers, but avoids the "set" problem described above, and allows easy delegation of methods. The main trick is to disable the creation of instances of the type:

    snit::type myensemble {
        pragma -hasinstances no

        typemethod set {key value} { ... }
    }

TODO

Nested ensemble objects (hint: oo::objdefine forward). More rationale? Link some of the wart discussions here for a solution (and clean them up).

See Also