Play It Again, Sam

by David Betz


Well, here I am again, writing about another tiny programming language.  You'd think that after writing one or two, I'd 
settle down to improving and supporting one.  Apparently, that isn't in the cards just yet.  It seems like every time I 
find a need for one of these little languages, the ones I've written before don't quite fill the bill and before you know it, 
I'm off to implementing a new one again.


Actually, there are may similarities between the languages I've built.  The bytecode compiler that I first designed for 
AdvSys, an old text adventure writing system, combined with stuff from XLISP was the basis for XScheme, my 
implementation of the Scheme language.  Similarly, an old language called ExTalk was the basis for the Bob language 
that I described in my September 1992 Dr. Dobbs article.  If you look closely at the source, you'll find that almost all 
of my languages share with each other.


So, when Dr. Dobbs asked me for yet another language for this issue, I decided to write about an offshoot of AdvSys 
that I'm working on.


A while back Activision re-released a bunch of the old Infocom text adventures in a collection called "The Lost 
Treasures of Infocom."  One day I found my daughter Rachel playing some of the old games.  It was nice to see her 
enjoying games that required her to use her imagination rather than the monotonous video games that kids tend to 
favor these days.  She enjoys writing so I asked her if should would have any interest in writing her own games and 
she said yes!  So, I dusted off an old copy of AdvSys and proceeded to try to bring it up-to-date.


For those of you who don't know about AdvSys, it is a simple, object-oriented system for writing text adventure 
games.  I designed it to be as small as possible and still capable of implementing fairly complex adventure games.  
The original version would run quite happily on a CP/M machine with 64K of RAM and the games it generated could 
have been made to run on much smaller machines.


Well, times have changed.  There is much more memory available on machines and it isn't unreasonable to assume 
that a program can have at least 512K of memory available to it.  Indeed, most Macintosh or Windows machines have 
far more than that.  Since there is  lots of memory available, why not use it?


The Environment


The original AdvSys consists of a separate compiler and interpreter.  You write a game by entering the source code in 
a text editor.  You then use the compiler to compile the source code into a data file that can be used by the interpreter 
to play the game.  This means that to fix a problem with a game, you have to go back to the source code, edit it and 
the recompile.  This process seemed to tedious for a nine year old.  I decided that the new system would be an 
interactive environment with a browser and the ability to build a game a little at a time and test each piece before 
moving on to the next.


The old AdvSys represented everything as 16 bit integers.  A reference to an object was simply a 16 bit offset into a 
table of objects.  This made good use of memory and fit well with my goal of running on small machines.  However, it 
caused some problems too.  There was no way to distinguish a number from an object reference and so it was 
impossible to build an automatic memory manager into the runtime module.  Consequently, AdvSys could not create 
objects at runtime.  Every object you wanted to use in a game had to be declared at compile time.


The new system, Drool, has an automatic memory manager with garbage collection and every value is represented by 
a 32 bit pointer.  Numbers are treated as a special case and are encoded into pointers and distinguished from them by 
setting the low order bit.  Since Drool only runs on byte addressed machines, it is easy to guarantee that all 
addresses are on an even byte boundary and hence have their low order bit cleared.  Thus, any value with its low 
order bit set is a number and every value with its low order bit cleared is an address.  A number is converted to a value 
by shifting it left by one bit position and oring the result with one.  It is converted back to a number by shifting the 
value to the right one.


Other types of objects are represented as pointers to objects in a heap.  Each object has a header that indicates its 
type.  So, the memory manager can distinguish different types and can garbage collect objects that are no longer 
reachable.  This makes it much easier to dynamically allocate objects and ensure that the memory they occupy is 
freed when the objects are no longer in use.


The Language


Rachel had never written a line of code in her life and I wanted to ease her into it a little at a time.  I thought it would be 
nice to have the system provide a collection of object types that she could assemble into a simple game without 
doing any programming at all.  The problem with that approach is that it can lead to very predictable games.  Once you 
know the sorts of objects that are available in to toolbox, you pretty much know what to expect of them when you 
encounter them in a game.  One way around this is to provide a bunch of object attributes that you can mix together in 
interesting combinations to create unique objects.  That way, she could invent a new type of object that would be 
different from any object in any other game, still without having to do any programming.


Well, that was the theory anyway.  To do that, I figured I needed to add multiple inheritance to the language.  AdvSys 
only supported single inheritance.  In fact, none of the tiny languages that I had designed supported multiple 
inheritance and I had only recently started to use it myself.


Before I go any further, I'd like to present small sample of Drool code so that you know what I'm talking about.  Here is 
an object definition and the definition of a method to operate on the object:


(defobject weapon ()

  (property 

    weight 10

    damage-points 20))


(defmethod (weapon 'damage)

  (getp self 'damage-points))


(defobject magical-weapon ()

  (property

    bonus 5))


(defmethod (magical-weapon 'damage)

  (let ((damage (call-next-method)))

    (+ damage (getp self 'bonus))))


(defobject magic-sword (magical-weapon weapon))


First, we define an object called `weapon' with two properties `weight' and `damage-points.'  Notice that unlike most 
object-oriented languages, there are no classes in Drool (or AdvSys), only objects.  Any object can act like a class or 
like an object.  We'll talk more about that later.  After defining the weapon object, we define a method that applies to 
the weapon object or any object that inherits from it.  This method is called `damage.'  You send a message to an 
object by using an expression like (sword `damage) where `sword' is the object and the quoted symbol after the object 
is the selector.  This selector is used to select a method for handling the message.  In the case of objects that inherit 
from `weapon,' the method we're describing is one of the methods that will apply.  The `getp' function fetches the value 
of a property of an object.  The `self' variable refers to the object receiving the message.


We then define another object `magic-weapon' with a single property `bonus.'  This object also has a method for the 
`damage' message.  In this case, the method is a bit more complicated.  The function (call-next-method) will call the 
next method that applies to the message being sent.


Whenever you send a message, it is possible that more than one method might apply.  If there is a method for that 
message defined for the object itself, that method will certainly apply.  Also, any methods for that message that are 
defined for objects that the receiving object inherits from will apply.


With a single inheritance system, method selection is fairly simple.  The most specific method is the one that will be 
called.  The most specific method is the method defined in the object closest to the object receiving the message in 
the object hierarchy.  When a method calls the function (call-next-method), the next most specific method is called.  
This can proceed back up the object hierarchy until there are no more applicable methods.


With multiple inheritance systems things are a bit more complicated.  Since an object can inherit from more than one 
other object, there can be more than one applicable method at each level in the hierarchy.  Drool resolves this conflict 
by choosing the method from the left-most object mentioned in the object definition and its ancestors before 
proceeding to the object to its right.  For example,the object magic-sword above inherits first from `magical-weapon' 
and then for `weapon.'  This means that when the `damage' message is sent to magic-sword, the first method to be 
called is the one defined for magical-weapon. Then, when the method for magical-weapon calls `call-next-method,' the 
method defined for weapon is called.


It's probably fairly obvious by now that I'm using a lisp-like syntax for Drool.  In fact, I've used a subset of Scheme, a 
simple dialect of Lisp, with an object system added.  For those of you not familiar with Scheme, the `let' construct 
above introduces and initializes local variables.  In the example above, the let construct defines the variable 
`damage'  and sets its initial value to the result of calling the call-next-method function.  That variable will then be 
available for the duration of the body of the let form, in this case, the expression (+ damage (getp self 'bonus)).


In addition to inheriting methods, an object also inherits properties.  In the case of the magic-sword object, it inherits 
the property `bonus' from magical-weapon and the properties `weight' and `damage-points' from weapon.  These 
properties are what other object systems call instance variables.  Each object has its own value for the property.  
Sometimes, it is handy to have a group of objects share a property value.  Drool allows this by providing shared 
properties.  When a new object is created, all of its normal property values are copied from the objects it inherits from, 
but shared property values are not copied, they are inherited like methods.  Shared properties are defined like normal 
properties except that you use the `shared-property' instead of the `property' keyword.


Along with objects and numbers, Drool also provides strings, lists and vectors as primitive data types.  Table 1 shows 
the complete syntax for Drool.  Because of the automatic storage management, you can create new objects at 
runtime. You do this with the `clone' function.  It creates and initializes a copy of an object.  To create a magic-sword, 
you might use the expression:


	(clone magic-sword 'weight 20 'damage-points 10 'bonus 8)


This creates a copy of the magic-sword object and sets the weight to 20, the damage-points to 10 and the bonus to 8.


Implementation


I'm writing Drool for the Macintosh and the current implementation includes an incremental compiler that reads Drool 
source code and generates bytecodes in memory where an interpreter executes them.  Memory is managed by a 
stop-and-copy garbage collector.  To make it easier to build the complex networks of objects that makeup an 
adventure game, I've provided an object browser.  Because the environment is interactive, you can design part of a 
game and then test it before going back to designing the rest.  When you're done, a `save workspace' facility allows 
you to write a data file containing the game.  The saved workspace allows  someone to play the game without having 
the source code.


What now?


While the Drool language is fairly complete, I'm just beginning the development environment.  To make it easier for 
children to use, I'm planning on building a facility for defining objects using templates instead of source code.  Let's 
face it, Lisp syntax isn't that easy to master and any textual language presents a barrier to non-programmers.  The 
templates will allow a game designer to create objects by combining preexisting objects like weapon and magical-
weapon using a direct manipulation interface.  The template would include fields for all of the inherited properties as 
well as any new properties the game designer might want to add.  At a higher level, objects representing actors and 
locations in the game could be arranged to form the game world and the behavior of objects at any level could be 
changed by adding methods that apply to those specific objects.  I've got a lot of work to do.  Language design was 
probably the easiest part, but I'm hoping that the resulting system will make it easier for children to build interesting 
and challenging adventure games.
