| [ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document:
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:
Amusingly, this help file is actually longer that the source code that implements GOLD.
GOLD is at least files:
inst creation function such that
all objects get sent the init message, immediately on creation.
init to *object*
(so if your class does not have an init method, then it still can be created
without a crash.
$prefix.
zlots.
with-zlots.
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*.
(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)
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.
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.
(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.
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))
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).
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))))
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.
See GOLD1 and 2; and GOLD3; and GOLD4.
| [ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on April 19, 2011 using texi2html 5.0.