GOLD: Graham's Object Language Definition
=========================================

This document:

  * Describes an object-oriented language called GOLD. Originally defined in Paul Graham's chapter on OO (grahamOO.pdf), GOLD contains some extensions by Tim Menzies (http://menzies.us).

  * Is a description of the upper layers of GOLD. For full details on all layers of GOLD, see Graham's text (grahamOO.pdf).

The point of GOLD is that a non-trivial OO language can be defined in just a few dozen lines of LISP. For example, GOLD supports:

  * classes;

  * instances;

  * methods;

  * extending methods by calling super-class methods;

  * and multiple inheritance.

Amusingly, this help file is actually longer that the source code that implements GOLD.

Installation
============

GOLD is at least files:

  * oo.lisp: Graham's original OO code (plus a few bug fixes);

  * gold.lisp: Some extensions, listed below.

  * xxx.lisp: Some class files.

Extensions
==========

  * GOLD defines a root object called *object*

  * GOLD  changes the inst creation function such that all objects get sent the init message, immediately on creation.

  * GOLD adds a "do nothing" method init to *object* (so if your class does not have an init method, then it still can be created without a crash.

  * GOLD lets you distinguish instance variables from method names using a $prefix.

  * GOLD defines an accessor that returns all the slots in an object: zlots.

  * GOLD defines an iterator over all slots in an object: with-zlots.

Examples
========

Subclassing
-----------

Something is a subclass of *object* with methods area,volume and instance variables $height.
(klass (*object*) area $height volume)
Note: in GOLD, everything has to be a subclass of *object*.

Creating a Global Class
-----------------------

(defparameter *body* (klass (*object*) area $height volume))
As a side-effect of the above call, set and get methods are defined for all the $variables. So, after that call, it is possible to call:
($height abody)
(setf ($height abody) 1)

Creating an Instance
--------------------

Example:
(inst *body*)

Note: inst is defined in terms of a lower-level inst0 function:
(defun inst (parent)
  (let ((obj (inst0 parent)))
    (init  obj)
    obj))
So, if you want to turn off auto-initialization, then use the lower-level command inst0.

Define a method
---------------

Methods are just like LISP functions, with at least one argument (the instance being processed).
(defmeth volume *body* (me)
         (* ($height me) (area me)))
Note: if you get this error:
Can't set #<FUNCTION (LAMBDA (U)) {10043C9DA9}>
    of #1=#((#2=#((#3=#)
               #(INIT
                 WITH-ZLOTS
                 ZLOTS
                 AREA
...
then have called defmeth on a method name not listed in the call to klass that defined this class.

Defining an Initialization Method
---------------------------------

(defmeth init *body* (me)
         (setf ($height me) 1))

Note that such methods are optional. All sub-classes of *object* inherit a default, do nothing, initialization method.

Extending a Super-class Method
------------------------------

Methods in sub-classes can access method definitions in super-classes via the next function.

For example, suppose a *body* has a default init action which a sub-class called *tube* wants to access:
(defmeth init *body* (u)
         (setf ($height u) 1))

(defmeth init *tube* (u)
         (next u)
         (setf ($radius u) 10))

Worked Example
==============

Bodies have a default height of one and a volume equal to their area times their height. Tubes are a sub-class of bodies whose area is their radius times pi, squared. Tubes initialize themselves as an extension to body's initialization.
(defparameter *body* (klass (*object*) area $height volume))
(defparameter *tube* (klass (*body*) $radius))

(defmeth init *body* (u)
         (setf ($height u) 1))

(defmeth area *tube* (u)
         (* pi (expt ($radius u) 2)))

(defmeth volume *body* (u)
         (* ($height u) (area u)))

(defmeth init *tube* (u)
         (next u)
         (setf ($radius u) 10))

(defun !tube ()
  (let ((tub (inst *tube*)))
    (format t "~a~%" (volume tub))
    (with-zlots tub
      #'(lambda (prop value)
          (if (dollarp prop)
              (format t "~a = ~a~%" prop value))))))
Note the functions with-zlots and dollarp in the !tube function. The former loops through all slot names while the latter selects anything that starts with a $ sign. This function just prints out all the instance variables (skipping over the functions).

Hints
=====

Functions that are generic to all objects can be written to *object* methods. For example:
(defmeth zlots *object* (self)
            (coerce (layout (parents self)) 'list))

(defmeth with-zlots *object* (self fn)
         (dolist (zlot (zlots self))
           (funcall fn zlot (lookup zlot self))))

Bugs
====

If *print-array* is non-nil, then display a class will lead to an infinite loop (since the first field contains a pointer back to itself, so a full print takes never terminates).

GOLD's source code sets *print-array*. However, in some obscure debugging scenarios, this is not enough to stop the infinite loop. Therefore,  if your code just hangs, restart LISP and make sure *print-array* is nil.

For More
========

See GOLD1 and 2 (http://unbox.org/wisp/var/timm/11/310/lisp/gold.html); and GOLD3 (http://unbox.org/wisp/var/timm/11/310/lisp/gold3.html); and GOLD4 (http://unbox.org/wisp/var/timm/11/310/lisp/gold4.html).