oo::configurable

The oo::configurable class is a part of TclOO in Tcl 8.7. It is a metaclass, i.e., it modifies how you create classes, adding the capability to define properties on the class. It also modifies the class to add a configure method (via a mixin). The configure method is aware of the properties defined across the inheritance hierarchy for the class.

Property names are constrained to be simple Tcl words (such that $word eq [list $word]) that don't contain :: or either ( or ). They also mustn't start with - because that will be added by the configure method.

Examples

In particular, this means that if one does:

oo::configurable create Point {
    property x y
    constructor args {
        my configure -x 0 -y 0 {*}$args
    }
    variable x y
    method print {} {
        puts "x=$x, y=$y"
    }
}

You can then do:

set pt [Point new -x 27]
$pt print;   # x=27, y=0
$pt configure -y 42
$pt print;   # x=27, y=42
puts "distance from origin: [expr {
    hypot([$pt configure -x], [$pt configure -y])
}]";         # distance from origin: 49.92995093127971
puts [$pt configure]
             # -x 27 -y 42

That can then be extended with more properties by a subclass:

oo::configurable create Point3D {
    superclass Point
    property z
    constructor args {
        next -z 0 {*}$args
    }
}

set pt2 [Point3D new -x 2 -y 3 -z 4]
puts [$pt2 configure]
              # -x 2 -y 3 -z 4

How it works

These details are subject to change, especially to improve the performance of the implementation. However, they're are intended to work much as if they are like this.

oo::configurable is a metaclass that does two things:

  1. It mixes the oo::configuresupport::configurable class into your class definition; that class contains the definition of the configure method.
  2. It sets up definition namespaces so you can say property in your definitions. That's in turn currently ultimately handled by the oo::configuresupport::PropertyImpl procedure (that's subject to change).
  3. When a property is created, it becomes an entry in the readable and writable properties slots (they're there in classes and objects but not visible by default) so that the property can be discovered, and a pair of methods, called (for a property foo) <ReadProp-foo> and <WriteProp-foo>; as you might expect with those names, they're not exported to the public API.
  4. The default implementation of those methods (you can provide your own) is to use my varname to look up the right variable (foo in our little example) and then to read or write it. That means that if you make that a private variable, the property will access the private variable, but subclasses will not be able to easily touch it by other mechanisms. (Future implementation note: do not count on the default implementations picking up any overriding of varname; that is unlikely to remain the way things work.)

A consequence of this is that if you make a read-only property in one configurable class, a write-only property with the same name in another configurable class, and then a third class that inherits from both, that third class will appear to have a read-write property.

These scripted parts of the implementation of TclOO (like others) are compiled into the Tcl C library. There isn't a script where they can be changed without a Tcl rebuild. This is because they are required before the I/O support is fully enabled when setting up an interpreter.