Proposal for MOO Light-Weight Objects

This is a counter-proposal to MOO WAIFs.

Implement the `table' datatype in MOO, in the same manner Pavel originally envisioned. (See also LPMOO's reference implementation.) Then, introduce a new builtin:

    bless(table, class) => blessed-table

You can think of `blessed-table' as a WAIF. It is, however, in all respects still a table. There is no need to assign an owner, however it probably shouldn't be possible to bless a table into a class that isn't fertile unless the programmer owns the class object.

Tables are immutable, therefore so are blessed tables. Therefore we don't have to worry about circular references; it can't happen. Garbage collection is the same as it is currently for lists. Smart copy-on-write allows efficient multiple references.

If a table has been blessed into a class, then:

    table.(property) => table[property] if it exists, else class.(property)
    table:(verb)()   => class:(verb)() with `this' == table

However, a blessed table must observe the following exceptions:

    table.name       => table["name"] if it exists, else ""
    table.location   => #-1
    table.contents   => {}
    table.programmer => 0
    table.wizard     => 0
    table.r          => 0
    table.w          => 0
    table.f          => 0

The .location and .contents are invariant to avoid placing references to blessed tables in either of these properties. (Calling move() with a blessed table argument is an error. The server could not guarantee any consistency anyway without tremendous overhead.) The last five invariants are for the safety of any code that might otherwise make assumptions about the table posing as an object.

I'm divided on whether parent(table) should return the class, since children(class) would not yield the table, and other builtins that take object arguments shouldn't necessarily be changed. Perhaps there should be a different builtin for this:

    classof(table) => class or #-1

On the other hand, existing code might have a better time not breaking if parent() were indeed overloaded. This should be examined more closely.

This design is nice because you only have to add one additional field to the table struct to record the class. Assuming you implement tables fully the way Pavel wanted, you also get a nice read syntax. You could even modify the syntax to support blessing at creation:

    {$class | "bar" ~ 3, "baz" ~ {1, 2}, #2 ~ "dark wizard"}

But maybe this isn't really necessary. Note, though, that blessed tables are free to store extra state other than property values, since table keys are not restricted to strings, and neither is it forbidden to create string keys which are not defined as properties on the class object. (Or you could stuff something in one of the invariant property names; table["wizard"] still works as expected even though table.wizard is always 0.)

Maybe a table isn't really a table, and it should be called something else. A `table' is really the same as a blessed table with class #-1.

More blessed table properties:

    table.(property) = value

is the same as:

    table[property] = value

(except for the invariant builtin properties, which raise E_PERM instead.) This is in turn the same as:

    table = bless({@{property ~ value}, @table}, classof(table))

Hopefully this was obvious, but just to be clear.

Also:

    is_clear_property(table, property)       => 0 iff table[property] exists
    clear_property(table, property)          => raise(E_PERM)

    property_info(table, property)           => raise(E_TYPE)
    set_property_info(table, property, info) => raise(E_TYPE)
    verb_info(table, verb)                   => raise(E_TYPE)
    set_verb_info(table, verb, info)         => raise(E_TYPE)

clear_property() must raise E_PERM since tables are not mutable. The same effect can be achieved, however, with:

    table = tabledelete(table, property)

assuming the table*() functions preserve the table's class.

The other builtins do not seem useful to implement against blessed tables, so they can simply raise E_TYPE.


Robert Leslie <rob@mars.org>