Go to the previous, next chapter.

The LambdaMOO Database

In this chapter, I begin by describing in detail the various kinds of data that can appear in a LambdaMOO database and that, therefore, MOO programs can manipulate. In a few places, I refer to the LambdaCore database. This is one particular LambdaMOO database, created every so often by extracting the ``core'' of the current database for the original LambdaMOO.

Note: The original LambdaMOO resides on the host lambda.parc.xerox.com (the numeric address for which is 13.2.116.36), on port 8888. Feel free to drop by! A copy of the most recent release of the LambdaCore database can be obtained by anonymous FTP from host parcftp.xerox.com in the directory pub/MOO.

Values

There are only a few kinds of values that MOO programs can manipulate:


The only numbers that MOO understands are the integers from -2^31 (that is, negative two to the power of 31) up to 2^31 - 1 (one less than two to the power of 31); that's from -2147483648 to 2147483647, enough for most purposes. In MOO programs, numbers are written just as you see them here, an optional minus sign followed by a non-empty sequence of decimal digits. In particular, you may not put commas, periods, or spaces in the middle of large numbers, as we sometimes do in natural languages (e.g., `2,147,483,647').

Character strings are arbitrarily-long sequences of normal, ASCII printing characters. When written as values in a program, strings are enclosed in double-quotes, like this:

"This is a character string."

To include a double-quote in the string, precede it with a backslash (\), like this:

"His name was \"Leroy\", but nobody ever called him that."

Finally, to include a backslash in a string, double it:

"Some people use backslash ('\\') to mean set difference."

MOO strings may not include special ASCII characters like carriage-return, line-feed, bell, etc. The only non-graphic characters allowed are spaces and tabs.

Objects are the backbone of the MOO database and, as such, deserve a great deal of discussion; the entire next section is devoted to them. For now, let it suffice to say that every object has a number, unique to that object. In programs, we write a reference to a particular object by putting a hash mark (#) followed by the number, like this:

#495

There are three special object numbers used for a variety of purposes: #-1, #-2, and #-3, usually referred to in the LambdaCore database as $nothing, $ambiguous_match, and $failed_match, respectively.

Errors are, by far, the least frequently used values in MOO. In the normal case, when a program attempts an operation that is erroneous for some reason (for example, trying to add a number to a character string), the server stops running the program and prints out an error message. However, it is possible for a program to stipulate that such errors should not stop execution; instead, the server should just let the value of the operation be an error value. The program can then test for such a result and take some appropriate kind of recovery action. In programs, error values are written as words beginning with E_. The complete list of error values, along with their associated messages, is as follows:

E_NONE      No error
E_TYPE      Type mismatch
E_DIV       Division by zero
E_PERM      Permission denied
E_PROPNF    Property not found
E_VERBNF    Verb not found
E_VARNF     Variable not found
E_INVIND    Invalid indirection
E_RECMOVE   Recursive move
E_MAXREC    Too many verb calls
E_RANGE     Range error
E_ARGS      Incorrect number of arguments
E_NACC      Move refused by destination
E_INVARG    Invalid argument
E_QUOTA     Object ownership quota exceeded

The final kind of value in MOO programs is lists. A list is a sequence of arbitrary MOO values, possibly including other lists. In programs, lists are written in mathematical set notation with each of the elements written out in order, separated by commas, the whole enclosed in curly braces ({ and }). For example, a list of the names of the days of the week is written like this:

{"Sunday", "Monday", "Tuesday", "Wednesday",
 "Thursday", "Friday", "Saturday"}

Note that it doesn't matter that we put a line-break in the middle of the list. This is true in general in MOO: anywhere that a space can go, a line-break can go, with the same meaning. The only exception is inside character strings, where line-breaks are not allowed.

Objects

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 numbers.

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.

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 LambdaMOO 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 function chparent() can change the parent and children attributes.

Properties

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 be read by any player.

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 publicly readable, 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.

Verbs

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 LambdaMOO 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 prints an error message on the terminal of the player whose command is being executed, and then aborts execution of the command. If the d bit is not set, then no message is printed and the command is not aborted; instead an error value (see the section on MOO values above) is returned as the result of the erroneous operation. This is useful for programs that are prepared to recover from such errors in an intelligent or productive manner. The d bit is usually set, however.

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.