<< >> Up Title Contents


4.5 Language Extensions


This section describes LiveWorld's extensions to Lisp. The facilities include accessors for boxes and their components, a message passing language defined on boxes.

4.5.1 Accessors for Boxes

Framer extends Lisp with the frame structure and accessors for its components (i.e., frame-home, frame-prototype). LiveWorld has a slightly modified set of functions for accessing annotations and grounds: names of boxes are given in the form of Lisp keywords, which are preceded with a colon and not evaluated.

(getb box name)
Returns the annotation of box named name, or generates an error if the annotation is not present.

(getb-safe box name)
Same as getb but returns nil rather than getting an error.

(getb-force box name &optional prototype)
Same as getb, but will create the frame if necessary (as a spinoff of prototype).

4.5.2 Message-Passing with ask

LiveWorld defines a message-passing protocol on boxes. When a box receives a message, which consists of a name and some optional arguments, it looks for an annotation with the same name as the message. This annotation should be a method object, which specifies an action (see the next section). In other words, methods are themselves boxes and are inherited by the usual mechanism. A single primitive, ask, is used both to send messages and to retrieve values from slots. The syntax of ask is as follows:

(ask box message arguments*)

Ask examines the annotation of box named by message. If it is a method, that method is applied to the box and arguments. If it's an ordinary slot, the value of the slot is retrieved and returned. For example:

(ask turtle :color) Returns the value of turtle's color slot.

(ask turtle :forward 10) Causes the turtle to move forward 10 pixels. There are also functions send and slot, which are like ask except that they always do a message send or a slot-lookup, respectively. This can be useful if a program wants to access a method object as a value rather than invoke it (something users would not ordinarily need to do).

ask-self is a variant of ask that can be used to access a slot or method directly. While ask is analogous to message-sending constructs in other languages, ask-self is rather unusual. It depends upon the fact that slots and methods are first-class objects and are local to their containing object: (ask-self slot-or-method arguments*)

will return the value in slot-or-method, or invoke it as a method if it is one. Ask-self is often used to extract a value from a box. Because this operation is quite common, it can be abbreviated as v for value. The following constructs are thus equivalent:

(ask box name)
(ask-self (getb
box name))

Setting values is done by sending them a :set message:

(ask slot :set value)

This allows objects to specify special actions to be performed on sets. For instance, computed slots (see section 4.6.3) get an error if an attempt is made to set their value. Because setting values is such a common operation, it may be abbreviated using the Common Lisp construct setf with a value accessing construct such as ask or v:

(setf (v slot) value)
(setf (ask
box slot) value)

4.5.3 Methods

Methods are written in Common Lisp augmented with Framer and LiveWorld extensions. There are several different kinds of methods, and it is possible for users to add further kinds. The system defines the following standard classes of methods:

Figure 4.9: A turtle with a simple method for :step messages.

Figure 4.9 illustrates a simple method for a turtle that implements a behavior. The method is named step, so that (ask #/circler/cast/turtle :step) will execute it. The method calls several other methods such as forward and turn-left, which are inherited from the prototype turtle and are not visible. The @^/ notation is a boxpath that refers to the turtle (see section 4.5.4.2). Triangle-sensor is a sensor (see section 4.6.4). The anima causes step to be called repeatedly (see section 4.6.1).

The body of a method can access several special symbols that are bound to values that indicate the local context. The symbol here is bound to the box in which the text of the expression appears. The symbol self is bound to the object which is the method's container. The symbol call-next is function-bound to a function that will invoke the method belonging to the object's prototype. This functionality is analogous to call-next-method in CLOS (Steele 1990), although the way in which next-methods are found in LiveWorld is very different. If a method calls call-next, the system follows the method's prototype link back until an appropriate next method is found. This allows any object to specialize a method while making use of the default behavior, and it also allows behaviors from one object to be imported to another, while preserving appropriate inheritance and calling paths.

Methods can have other slots besides their body and arguments. Among the standard defined slots are documentation, whose value can be an explanatory string, and command-key, whose value is a character which will make the method invokable by a keyboard command when the parent object is selected (see Figure 4.6).

4.5.4 Relative Box Reference

Methods often need to refer to their containing object or to other boxes. Absolute box names are usually not suitable because they will break if the method is cloned. Methods thus need to refer to boxes in relation to their own location.

4.5.4.1 Self

The simplest way to handle relative reference is through a special variable that refers to the local object. In many other OOP languages this variable is called self, and LiveWorld continues that tradition. In the body of a method, the name self can be used to refers to the object that contains the method. However, LiveWorld's hierarchical object system generates needs for more complex forms of relative reference. Also, the name self is somewhat confusing in the context of a hierarchical object system: it might just as logically be taken to refer to the box in which it occurs, rather than the box for which it is a method, which might be several levels up in the hierarchy.

4.5.4.2 Boxpaths

To solve these problems, I defined a new syntax for boxpaths, which provides a more flexible facility for relative reference to boxes and their values. Boxpaths specify a relative path from one box to another. Boxpaths are always specified relative to the box in which they occur, removing the ambiguity of self. Boxpaths also allow reference based on types. For instance, a boxpath can specify paths that say "go up to the nearest enclosing actor box and then get the value from its prey-sensor's other slot."

Boxpath syntax is based on Framer's default syntax. An @ introduces a boxpath, and following characters specify navigation paths through the box hierarchy, either up or down. A caret (^) means "go up", that is, access an ancestor of the current box. A boxpath can go a fixed number of steps up the container hierarchy, or it can search upwards for a particular kind of box. Downward navigation is expressed by the standard frame syntax (see 4.3.1) but with an extension that allows box values, as well as boxes themselves, to be accessed. This extension is based on Unix directory naming conventions, with a box treated analogously to a directory. A final / in a boxpath indicates that the path is to return the final box in the path, while the absence of a final / indicates that the final box's value should be returned. Some examples of how boxpaths express common patterns of box reference:
@/
The local box (the box in which the boxpath appears).
@
The value of the local box.
@^/
The immediate container of the local box.
@^/food-sensor
The value of the box named food-sensor that is a sibling of the local box.
@^^/
The container of the immediate container.
@^actor/prey-sensor/other
The example above: "go up to the nearest enclosing actor box and then get the value from its prey-sensor's other slot."
Boxpaths are essentially a syntactic abbreviation for complex sequences of box accessing functions. For example, the last example above expands into the Lisp code:

(ask (getb (lookup-box *here* :actor) 

           :prey-sensor) 

     :other)

Where *here* is bound to the box in which the boxpath appears. Lookup-box is a function that searches up the box hierarchy for a box of a specified type.

4.5.5 Demons

The standard :set method includes a facility for establishing demons on a slot. These are procedures that get executed whenever the value of a slot changes. While similar effects can be accomplished by defining a local :set method, the advantage of demons are that they can be easily added dynamically, and if there are more than one they will not interfere with each other (that is, a box can have many demons, while it can have at most one local :set method). LiveWorld uses demons for many internal functions, such as invalidating computed slots (see 4.6.3) and updating the display of graphic actors if one of their parameters should change. Demons are stored in an internal annotation (name %demons) and are inherited by clones of the parent object. To avoid the potential of infinite recursion, the %demons slot itself has a :set method for that prototype that avoids the usual demon mechanism.

The demon mechanism can generalize to handle other types of events besides value changes. For instance, boxes can also have annotation demons that get called whenever an annotation is added to or removed. A typical use is for a sensor to put an annotation demon on the cast box of a theater, so that it can be informed whenever a new actor appears in the world.

4.5.6 Global Object

The inheritance scheme of Framer was modified to include the concept of a global default prototype. Named #/global, this box serves as a last resort when looking up slots. This object provides the default methods for common operations such as :set, the default annotations for interface operations such as click tables, and default templates for universally shared slots, such as documentation and %demons.


[15]The existence of primitive methods is an artifact of the way in which LiveWorld was bootstrapped, and they could be eliminated.


<< >> Up Title Contents