MOO-cows Mailing List Archive
Re: "verbing properties" and related issues
Here is a document I worked up the last time "verbing properties" was
addressed on this list...it's a proposal based very loosely on C++. If
people have suggestions, I'd love to hear them. If people express real
interest in using this in a production setting, I'll work on the hack as
soon as the debugger is stable....
Draft MOO Encapsulation Standard
The MOO encapsulation standard is designed to address a perceived
shortcoming in the MOO server's handling of access control. The existing
(v1.8.0p5) MOO access control is based solely on an operating system
model. Objects, properties, and verbs have owners and permission bits
very reminiscent of those found in a UNIX-like file system. Current MOO
permission checking is designed to maintain security in a multi-user
MOO should, however, be viewed as a programming language as well. The
MOO programming language has no practical method of enforcing
encapsulation. This lack of enforcable encapsulation has produced
several unfortunate side effects. Most notable among these is a lack of
"reusable objects". One of the chief advantages cited for object-
oriented programming is the reusability of code in an OO environment. It
is worth noting that there are virtually no generic objects being shared
by the MOO community. Generally, interdependent groups blocks of objects
(cores) are created; this seems to violate the spirit of object-oriented
Enforced encapsulation would address several concerns raised on the
MOO-Cows mailing list. It includes support for verb "overridability"
control. It would also serve as a solution for those programmers who
wanted to "verb properties"--that is, force all property access to go
through MOO verbs. In fact, the features mentioned here (many of which
are admittedly based on C++) represent a feasible solution to the very
real problem noticed by the people interested in verbing properties.
Under the proposed encapsulation modifications, all tasks would have a
scope associated with them. This scope would be the object on which the
currently running verb *is defined*--NOT the value of this, and
definitely not the value of player. Note that this represents a drastic
departure from current MOO access control methods, which operate based on
the player 'responsible' for a given task. The ability to run a task
under a non-standard scope is addressed later in this document.
THE OVERRIDE BIT
The override (O) bit is a new permission bit added to all verbs under
the proposed encapsulation standard. A verb called on an object, such as
#99:tell(), would *not* look first at #99:tell(). Rather, it would begin
searching from the top of #99's ancestor list. The first non-overridable
:tell verb it found would be selected for execution. Thus, if #99's
parent was #54, whose parent was #1, and #54 defined a -O :tell() verb,
#54:tell() would be executed with this = #99. If, however, #54:tell()
was +O and #99:tell() existed, #99:tell() would be called (with this =
#99, of course). The best analogy for this is the virtual keyword in
SCOPED VERB CALLS
If the verb #99:tell() existed, but #54:tell() was set -O, there would
be a way to call #99:tell() directly using would use scoped verb calls.
The syntax of a scoped verb call is
Or, more generally,
This would raise an error if <#verb location> was not <#this> or an
ancestor of <#this>. The placement of the double-colon between the two
object numbers rather than between the verb location and the verb name is
needed to implement this syntax in a LALR, 1-lookahead token parser.
PUBLIC, PRIVATE and HEREDITARY
These are the access modifiers responsible for enforcing encapsulation.
All properties, verbs, and objects can be set P (public), H (hereditary),
or neither (private). The effects of public, private, and hereditary
scope for objects, verbs and properties are discussed below.
A public property behaves just as a MOO property currently does. That
is, it can be read and modified by tasks running in *any* scope. A
hereditary property may be seen and modified *only* by tasks running in
the scope of the object on which the property *is defined* or a
descendent thereof. A private property may be seen and modified only by
a verb in the scope of the object on which the property is defined. An
attempt to access a property unavailable to the current scope raises
Note that, if #54 defines a private property .foobar, then #99.foobar
is visible only to the scope of #54--NOT to the scope of #99. This
permits true encapsulation and data abstraction in a way that MOO
currently does not.
A public verb behaves just as a MOO verb currently does (see below).
It may be called by a verb from any other scope. A hereditary verb may
be called only by scope of the object on which it is defined or an
ancestor of that object. A private verb may be called only by another
verb in the scope of the object on which it is defined. A hereditary or
private verb is treated as if it did not exist when searching for a verb
to execute unless the current scope can see the verb. If #54:tell()
existed, was -O, but was private, then a call to #99:tell() from any
scope but #54 would not see the -O verb #54:tell() and would ascend to
The C++ analogy for these permissions is, of course,
public/protected/private. Unfortunately, all begin with 'P', making my
life and yours just a bit more difficult.
At some point, programmers are inevitably going to want to operate in a
different scope than they are currently using--especially with eval,
whose scope is #-1, meaning it is private to no object.
Three proposals are presented below, from most strict to least. I am
in favor of 1 or 2, and really want to avoid 3.
1) You can't alter scope. If you want to alter a private property or
call a private verb, set it public, change it, and set it back. If you
don't suspend, you're completely safe.
2) eval("<program>", <#scope>). It could also be called with 1 argument,
of course, in which case the scope is #-1. The scope could only be that
of an object owned by a programmer, or any object if the programmer was a
wizard. This at least makes it a pain to run tasks under different
scopes while making it possible to set values of private properties.
3) set_task_scope(<#scope>). It would, of course, make the same
permission checks that eval in 2) did. Its existence, however, goes
contrary to everything that encapsulation is trying to accomplish. I
mention it mostly so I can mention it and refute it, rather than having
someone else bring it up.
Subject Index |