[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2 Objects in the MOO Database

Objects are, in a sense, the whole point of the MOO programming language. They are used to represent objects in the virtual reality, like people, rooms, exits, and other concrete things. Because of this, MOO makes a bigger deal out of creating objects than it does for other kinds of value, like integers.

Numbers always exist, in a sense; you have only to write them down in order to operate on them. With objects, it is different. The object with number ‘#958’ does not exist just because you write down its number. An explicit operation, the ‘create()’ function described later, is required to bring an object into existence. Symmetrically, once created, objects continue to exist until they are explicitly destroyed by the ‘recycle()’ function (also described later).

The identifying number associated with an object is unique to that object. It was assigned when the object was created and will never be reused, even if the object is destroyed. Thus, if we create an object and it is assigned the number ‘#1076’, the next object to be created will be assigned ‘#1077’, even if ‘#1076’ is destroyed in the meantime.

Every object is made up of three kinds of pieces that together define its behavior: attributes, properties, and verbs.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.1 Fundamental Object Attributes

There are three fundamental attributes to every object:

  1. A flag (either true or false) specifying whether or not the object represents a player,
  2. The object that is its parent, and
  3. A list of the objects that are its children; that is, those objects for which this object is their parent.

The act of creating a character sets the player attribute of an object and only a wizard (using the function set_player_flag()) can change that setting. Only characters have the player bit set to 1.

The parent/child hierarchy is used for classifying objects into general classes and then sharing behavior among all members of that class. For example, the LambdaCore database contains an object representing a sort of “generic” room. All other rooms are descendants (i.e., children or children's children, or …) of that one. The generic room defines those pieces of behavior that are common to all rooms; other rooms specialize that behavior for their own purposes. The notion of classes and specialization is the very essence of what is meant by object-oriented programming. Only the functions create(), recycle(), chparent(), and renumber() can change the parent and children attributes.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.2 Properties on Objects

A property is a named “slot” in an object that can hold an arbitrary MOO value. Every object has eight built-in properties whose values are constrained to be of particular types. In addition, an object can have any number of other properties, none of which have type constraints. The built-in properties are as follows:

 
name         a string, the usual name for this object
owner        an object, the player who controls access to it
location     an object, where the object is in virtual reality
contents     a list of objects, the inverse of ‘location
programmer   a bit, does the object have programmer rights?
wizard       a bit, does the object have wizard rights?
r            a bit, is the object publicly readable?
w            a bit, is the object publicly writable?
f            a bit, is the object fertile?

The ‘name’ property is used to identify the object in various printed messages. It can only be set by a wizard or by the owner of the object. For player objects, the ‘name’ property can only be set by a wizard; this allows the wizards, for example, to check that no two players have the same name.

The ‘owner’ identifies the object that has owner rights to this object, allowing them, for example, to change the ‘name’ property. Only a wizard can change the value of this property.

The ‘location’ and ‘contents’ properties describe a hierarchy of object containment in the virtual reality. Most objects are located “inside” some other object and that other object is the value of the ‘location’ property. The ‘contents’ property is a list of those objects for which this object is their location. In order to maintain the consistency of these properties, only the move() function is able to change them.

The ‘wizard’ and ‘programmer’ bits are only applicable to characters, objects representing players. They control permission to use certain facilities in the server. They may only be set by a wizard.

The ‘r’ bit controls whether or not players other than the owner of this object can obtain a list of the properties or verbs in the object. Symmetrically, the ‘w’ bit controls whether or not non-owners can add or delete properties and/or verbs on this object. The ‘r’ and ‘w’ bits can only be set by a wizard or by the owner of the object.

The ‘f’ bit specifies whether or not this object is fertile, whether or not players other than the owner of this object can create new objects with this one as the parent. It also controls whether or not non-owners can use the chparent() built-in function to make this object the parent of an existing object. The ‘f’ bit can only be set by a wizard or by the owner of the object.

All of the built-in properties on any object can, by default, be read by any player. It is possible, however, to override this behavior from within the database, making any of these properties readable only by wizards. See the chapter on server assumptions about the database for details.

As mentioned above, it is possible, and very useful, for objects to have other properties aside from the built-in ones. These can come from two sources.

First, an object has a property corresponding to every property in its parent object. To use the jargon of object-oriented programming, this is a kind of inheritance. If some object has a property named ‘foo’, then so will all of its children and thus its children's children, and so on.

Second, an object may have a new property defined only on itself and its descendants. For example, an object representing a rock might have properties indicating its weight, chemical composition, and/or pointiness, depending upon the uses to which the rock was to be put in the virtual reality.

Every defined property (as opposed to those that are built-in) has an owner and a set of permissions for non-owners. The owner of the property can get and set the property's value and can change the non-owner permissions. Only a wizard can change the owner of a property.

The initial owner of a property is the player who added it; this is usually, but not always, the player who owns the object to which the property was added. This is because properties can only be added by the object owner or a wizard, unless the object is publicly writable (i.e., its ‘w’ property is 1), which is rare. Thus, the owner of an object may not necessarily be the owner of every (or even any) property on that object.

The permissions on properties are drawn from this set: ‘r’ (read), ‘w’ (write), and ‘c’ (change ownership in descendants). Read permission lets non-owners get the value of the property and, of course, write permission lets them set that value. The ‘c’ permission bit is a little more complicated.

Recall that every object has all of the properties that its parent does and perhaps some more. Ordinarily, when a child object inherits a property from its parent, the owner of the child becomes the owner of that property. This is because the ‘c’ permission bit is “on” by default. If the ‘c’ bit is not on, then the inherited property has the same owner in the child as it does in the parent.

As an example of where this can be useful, the LambdaCore database ensures that every player has a ‘password’ property containing the encrypted version of the player's connection password. For security reasons, we don't want other players to be able to see even the encrypted version of the password, so we turn off the ‘r’ permission bit. To ensure that the password is only set in a consistent way (i.e., to the encrypted version of a player's password), we don't want to let anyone but a wizard change the property. Thus, in the parent object for all players, we made a wizard the owner of the password property and set the permissions to the empty string, "". That is, non-owners cannot read or write the property and, because the ‘c’ bit is not set, the wizard who owns the property on the parent class also owns it on all of the descendants of that class.

Another, perhaps more down-to-earth example arose when a character named Ford started building objects he called “radios” and another character, yduJ, wanted to own one. Ford kindly made the generic radio object fertile, allowing yduJ to create a child object of it, her own radio. Radios had a property called ‘channel’ that identified something corresponding to the frequency to which the radio was tuned. Ford had written nice programs on radios (verbs, discussed below) for turning the channel selector on the front of the radio, which would make a corresponding change in the value of the ‘channel’ property. However, whenever anyone tried to turn the channel selector on yduJ's radio, they got a permissions error. The problem concerned the ownership of the ‘channel’ property.

As I explain later, programs run with the permissions of their author. So, in this case, Ford's nice verb for setting the channel ran with his permissions. But, since the ‘channel’ property in the generic radio had the ‘c’ permission bit set, the ‘channel’ property on yduJ's radio was owned by her. Ford didn't have permission to change it! The fix was simple. Ford changed the permissions on the ‘channel’ property of the generic radio to be just ‘r’, without the ‘c’ bit, and yduJ made a new radio. This time, when yduJ's radio inherited the ‘channel’ property, yduJ did not inherit ownership of it; Ford remained the owner. Now the radio worked properly, because Ford's verb had permission to change the channel.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.3 Verbs on Objects

The final kind of piece making up an object is verbs. A verb is a named MOO program that is associated with a particular object. Most verbs implement commands that a player might type; for example, in the LambdaCore database, there is a verb on all objects representing containers that implements commands of the form `put object in container'. It is also possible for MOO programs to invoke the verbs defined on objects. Some verbs, in fact, are designed to be used only from inside MOO code; they do not correspond to any particular player command at all. Thus, verbs in MOO are like the `procedures' or `methods' found in some other programming languages.

As with properties, every verb has an owner and a set of permission bits. The owner of a verb can change its program, its permission bits, and its argument specifiers (discussed below). Only a wizard can change the owner of a verb. The owner of a verb also determines the permissions with which that verb runs; that is, the program in a verb can do whatever operations the owner of that verb is allowed to do and no others. Thus, for example, a verb owned by a wizard must be written very carefully, since wizards are allowed to do just about anything.

The permission bits on verbs are drawn from this set: ‘r’ (read), ‘w’ (write), ‘x’ (execute), and ‘d’ (debug). Read permission lets non-owners see the program for a verb and, symmetrically, write permission lets them change that program. The other two bits are not, properly speaking, permission bits at all; they have a universal effect, covering both the owner and non-owners.

The execute bit determines whether or not the verb can be invoked from within a MOO program (as opposed to from the command line, like the ‘put’ verb on containers). If the ‘x’ bit is not set, the verb cannot be called from inside a program. The ‘x’ bit is usually set.

The setting of the debug bit determines what happens when the verb's program does something erroneous, like subtracting a number from a character string. If the ‘d’ bit is set, then the server raises an error value; such raised errors can be caught by certain other pieces of MOO code. If the error is not caught, however, the server aborts execution of the command and, by default, prints an error message on the terminal of the player whose command is being executed. (See the chapter on server assumptions about the database for details on how uncaught errors are handled.) If the ‘d’ bit is not set, then no error is raised, no message is printed, and the command is not aborted; instead the error value is returned as the result of the erroneous operation.

Note: The ‘d’ bit exists only for historical reasons; it used to be the only way for MOO code to catch and handle errors. With the introduction of the try-except statement and the error-catching expression, the ‘d’ bit is no longer useful. All new verbs should have the ‘d’ bit set, using the newer facilities for error handling if desired. Over time, old verbs written assuming the ‘d’ bit would not be set should be changed to use the new facilities instead.

In addition to an owner and some permission bits, every verb has three `argument specifiers', one each for the direct object, the preposition, and the indirect object. The direct and indirect specifiers are each drawn from this set: ‘this’, ‘any’, or ‘none’. The preposition specifier is ‘none’, ‘any’, or one of the items in this list:

 
with/using
at/to
in front of
in/inside/into
on top of/on/onto/upon
out of/from inside/from
over
through
under/underneath/beneath
behind
beside
for/about
is
as
off/off of

The argument specifiers are used in the process of parsing commands, described in the next chapter.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Roger Crew on March, 27 2010 using texi2html 1.78.