Contents
Back
Forward

8. Introducing messages and classes


On a round ball
A workman that hath copies by, can lay
An Europe, Afrique and an Asia,
And quickly make that, which was nothing, All.

...John Donne (1571?--1631), Valediction: Of Weeping

In fact, messages have already appeared in Section 7. Recall from Section 3 that a message called messagename can be sent to an object called objectname with various supplied details (called info1 and info2 here, though there can be any number from none to 6) as follows:

       objectname.messagename(info1, info2);
And the given object sends back a reply value (which is just a single quantity). This is what is really happening when the player tries to eat the mushroom: first the library sends the mushroom a before message to warn it that something will happen; it might reply true, in which case the library gives up; otherwise the eating takes place, and the library sends an after message to inform the mushroom of its demise.

Properties like before, then, are really rules to deal with incoming messages. The same applies to most of the properties in Section 3. For example, the message

       mushroom.description();
is sent when the player tries to examine the mushroom: if the reply is false then the game prints "You see nothing special about the speckled mushroom.'' Now the mushroom was set up with
       description
          "The mushroom is capped with blotches, and you aren't at all sure
           it's not a toadstool.",
which doesn't look like a rule for receiving a message, but it is one all the same: it means "print this text out, print a new-line and reply true''. A more complicated rule could have been given instead, as in the following elaboration of the stone-cut steps in 'Ruins':
       description
       [;  print "The cracked and worn steps descend into a dim chamber.
                  Yours might ";
           if (Square_Chamber has visited)
                print "be the first feet to tread";
           else print "have been the first feet to have trodden";
           " them for five hundred years.  On the top step is inscribed
            the glyph Q1.";
       ],
visited is an attribute which is currently held only by rooms which the player has been to. (The glyphs will be explained later on, as will the SquareChamber room, which is where the steps will lead down into.)

The library, i.e., the standard game rules, can send out about 40 different kinds of message, before and description being two of these. The more interesting an object is, the more ingeniously it will respond to these messages: an object which ignores all incoming messages will be lifeless and inert in play, like a small stone.

/\/\ In fact there are subtle differences between how the library uses properties, and message-sending: the name property, for example, is not really a message-receiver but is just what it appears to be -- a list of useful data. Also, the library is careful not to send (for instance) a description message to an object which doesn't provide a rule for what to do with one. But the idea is right.

So the library is sending out messages to your objects all the time during play. Your objects can also send each other messages, including "new'' ones that the library would never send. It's sometimes convenient to use these to trigger off happenings in the game. For example, suppose the 'Ruins' are home to a parrot which squawks from time to time, for a variety of reasons:

Object -> parrot "red-tailed parrot"
  with name "red" "tailed" "red-tailed" "parrot" "bird",
       description
          "Beautiful plumage.",
       squawk
       [ utterance;
           if (self in location)
               print "The parrot squawks, ~", (string) utterance,
                   "! ", (string) utterance, "!~^";
       ],
  has  animate;
We might then, for instance, change the after rule for dropping the mushroom to read:
           Drop: parrot.squawk("Drop the mushroom");
                 "The mushroom drops to the ground, battered slightly.";
so that the wretched creature would squawk "Drop the mushroom! Drop the mushroom!'' each time this was done. Likewise, squawk messages could be sent for any number of other reasons connected with other objects. But at present it would be an error to send a squawk message to any object other than the parrot, since only the parrot has been given a rule telling it what to do if it receives one.

??EXERCISE 2:
(link to
the answer)
Make a medicine bottle, which can be opened in a variety of ways in the game, so that the opening--code only occurs once in the bottle definition.

In most games there are groups of objects with certain rules in common, which it would be tiresome to have to write out many times. For making such a group, a class definition is the better technique. These closely resemble object definitions, but since they define prototypes rather than actual things, they have no initial location. (An individual tree may be somewhere, but the concept of being a tree has no particular place.) So the 'header' part of the definition is simpler.

For example, the scoring system in 'Ruins' works as follows: the player, an archaeologist of the old school, gets a certain number of points for each 'treasure' (i.e., cultural artifact) he can filch and put away into his packing case. This is implemented with the following class:

 Class Treasure
  with cultural_value 10,
       after
       [; Insert:
                if (second==packing_case)
                    score = score + self.cultural_value;
                "Safely packed away.";
       ],
       before
       [; Take, Remove:
                if (self in packing_case)
                   "Unpacking such a priceless artifact had best wait
                    until the Metropolitan Museum can do it.";
       ];
Note that self is a variable, which always means "whatever object I am''. If we used it in the definition of the mushroom it would mean the mushroom: used here, it means whatever treasure happens to be being dealt with. (Explanations about Insert and Remove will come later, but hopefully the idea is clear enough.) An object of the class Treasure inherits the properties and attributes it defines: in this case, an object of class Treasure picks up the given score and rules automatically. So
Treasure statuette "pygmy statuette"
  with description
          "A menacing, almost cartoon-like statuette of a pygmy spirit
           with a snake around its neck.",
       initial "A precious Mayan statuette rests here!",
       name "snake" "mayan" "pygmy" "spirit" "statue" "statuette";
inherits the cultural_value score of 10 and the rules about taking and dropping. If the statuette had itself set cultural_value to 15, say, then the value would be 15, because the object's actual definition always takes priority over anything the class might have specified.

A more unusual artifact:

Treasure honeycomb "ancient honeycomb"
  with article "an",
       name "ancient" "old" "honey" "honeycomb",
       description "Perhaps some kind of funerary votive offering.",
       initial "An exquisitely preserved, ancient honeycomb rests here!",
       after
       [;  Eat: "Perhaps the most expensive meal of your life.  The honey
               tastes odd, perhaps because it was used to store the entrails
               of the king buried here, but still like honey.";
       ],
  has  edible;
The honeycomb now has two after rules: a new one of its own, plus the existing one that all treasures have. Both apply, but the new one happens first.

/\ So comparing cultural_value and after, there seems to be an inconsistency. In the first case, an object's own given value wiped out the value from the class, but in the second, the two values were joined up into a list. Why? The reason is that some of the library's properties are special (again) in being what's called "additive'', so that their values accumulate into a list when class inheritance takes place. The three useful examples are before, after and name.

/\/\ Non-library properties you invent (like squawk or cultural_value) will never be additive, unless you write a directive like:
Property additive squawk;
(before squawk is otherwise mentioned) to say so.

Finally, note that an object can inherit from several classes at once (see Section 3 for how to give such a definition). Moreover, a class can itself inherit from other classes, so it's easy to make a class for "like Treasure but with cultural_value normally 8 instead of 10''.

*REFERENCES:
See 'Balances' for an extensive use of message-sending.
'Advent' has a treasure-class similar to this one, and uses class definitions for the many similar maze and dead-end rooms (and the sides of the fissure).
That class definitions can be worthwhile even when only two objects use them, can be seen from the kittens-class in 'Alice Through The Looking-Glass'.
'Balances' defines many complicated classes: see especially the white cube, spell and scroll classes.
'Toyshop' contains one easy one (the wax candles) and one unusually hard one (the building blocks).

Contents / Back / Forward
Chapter I / Chapter II / Chapter III / Chapter IV / Chapter V / Chapter VI / Appendix
Mechanically translated to HTML from third edition as revised 16 May 1997. Copyright © Graham Nelson 1993, 1994, 1995, 1996, 1997: all rights reserved.