clon

About

CLON stands for Common Lisp Object Network. It is different from CLOS in several important ways:

  • CLON is prototype-based, not class-based. A prototype is a template object from which other objects are "cloned".
  • Method invocation happens via message-passing, not generic functions; messages are conceptually different from synchronous function calls and may be freely queued, forwarded, and filtered.
  • Built-in support for serialization.
  • Simple and small: as of December 2008, clon.lisp contains about 750 lines of code and commentary.
  • Special syntax support for message sending:
      [method-name object arg1 arg2 ...]
    

    and for accessing fields (i.e. "slots" in CLOS terminology):

      (setf <field-name> value)
    

Download

Code example

First we must define a prototype and its fields:

(define-prototype rectangle ()
  x y width height)

We could also have provided initialization forms and documentation strings:

(define-prototype rectangle ()
  (x :initform 0 
     :documentation "The x-coordinate of the rectangle's top-left corner.")
  (y :initform 0 
     :documentation "The y-coordinate of the rectangle's top-left corner.")
  (width :documentation "The width of the rectangle.")
  (height :documentation "The height of the rectangle."))

And if there was a "shape" prototype, from which we would like "rectangle" to inherit data and methods, we might have written:

(define-prototype rectangle (:parent =shape=)
  (x :initform 0 
     :documentation "The x-coordinate of the rectangle's top-left corner.")
  (y :initform 0 
     :documentation "The y-coordinate of the rectangle's top-left corner.")
  (width :documentation "The width of the rectangle.")
  (height :documentation "The height of the rectangle."))

Notice the equals signs surrounding the parent object's name; all objects made with define-prototype are accessible via special variables with such names.

The function CLON:CLONE is used to create new objects from these prototypes. Now we write an initializer, which is passed any creation arguments at the time of cloning:

(define-method initialize rectangle (&key width height)
  (setf <width> width)
  (setf <height> height))

Notice how field accesses can be written with the angle brackets; this works both for reading and for writing, so long as you use setf for the latter.

Now when you say:

(clone =rectangle= :width 5 :height 12)

The rectangle's initializer method is invoked with those arguments, and a rectangle of the correct height and width is created.

Now we define a few methods:

(define-method area rectangle ()
  (* <width> <height>))

(define-method print rectangle (&optional (stream t))
  (format stream "height: ~A width: ~A area: ~A"
        <height> <width> 
        [area self]))

And invoke them with the aforementioned square bracket notation:

(defvar rect (clone =rectangle= :width 10 :height 8))

[print rect]

The result:

"height: 8 width: 10 area: 80"

Author: David O'Toole <dto@gnu.org>

Date: 2009-09-22 06:21:28 EDT

HTML generated by org-mode 6.30trans in emacs 23