All atoms are stored as pairs (class, instance). The class
component provides informations about the general properties of that
kind of atom. The instance component contains the properties of
this specific atom in particular. Classes themselves are unnamed atoms,
stored as value of certain symbols. For example, classes are instances
of the class class (i.e. of the class
stored as the value of the symbol class
).
3.10.0. Object Terminology
|
|
A class defines two major kinds of information:
- An atom can contain storage for one or several lisp objects.
Such storage areas are called slots , and have symbolic names. A
class defines the number of slots allocated in a new atom as well as
their names. This slot information is statically defined by the
defclass function during class definition;
- Atoms can receive messages sent with the function ==> .
Messages are identified by a symbol called the message selector .
A class defines the possible message selectors and functions (i.e
methods) to execute when it receives such messages. These methods
are dynamically defined with the putmethod
function.
In addition, predefined classes associated with standard Lush objects
often have hidden properties. Such classes are special and do not
inherit from the object class. For
example, a symbol has some storage for its value; the storage is not a
slot. A symbol also returns its value when it is evaluated; this
behavior is not a method.
New classes defined with the defclass
function are always subclasses of another class (i.e. its superclass).
The superclass itself may have its own superclasses. In this way:
- A class inherits the slots of its superclasses . When a
new object is created, space is allocated for the slots defined by its
class and also for the slots defined by all of its superclasses;
- A class inherits the methods of its superclasses . When an
object receives a message with a given selector, it searches the methods
defined by its class for the selector. If no method is found that
matches the selector it searches the methods of its superclass, the
methods of the superclass of its superclass, and so on. When it reaches
a matching method it executes the associated function in the context of
the class that defines the matching method.
3.10.2. Predefined Classes
|
|
Here is a compact list of the main predefined classes. Most of them are
named using uppercase symbols, which ought to be surrounded with bars to
avoid the usual lowercase conversion:
- object : the root class of
most user defined classes;
- class : classes are actually lisp
objects, instance of the class class.
Thus, class class is an instance of
itself;
- |NUMBER| : the class of the
numbers;
- |LIST| : the class of the pairs
used for building lists;
- |SYMB| : the class of the
symbols;
- |STRING| : the class of the
strings;
- |DE| |DF|
|DM| |DX|
|DY| : the classes of functions;
- and so on.
All user defined classes must be direct or indirect subclasses of the
class object . You cannot inherit a
predefined class like |SYMB| , it is
not a subclass of object . The
object class defines a regular lisp object with no hidden
properties. Instances of subclasses of the class
object are easily created with the function
new .
3.10.3.0. (defclass name superclass s1 ... sn)
|
[DM] |
Defines a subclass of class superclass
with slots s1 ...
sn . The class is stored into symbol
name , which is returned. Slot specifications
s1 ... sn can be symbols or
lists (symbol default) which indicate
initial values assigned to the slots of a new object.
Example:
;;; Creates a class <rect> with two slots: <width> and <height>.
? (defclass rect object
width height )
= rect
;;; Creates a subclass of <rect>,
;;; plus an additional slot <name> with default value <"noname">.
? (defclass namedrect rect
(name "noname") )
= namedrect
3.10.3.1. (makeclass classname superclass slotnamelist slotdefaultlist)
|
[DX] |
This a lower-level function to create a new class named
classname . Most user will prefer to use
defclass instead. The new class inherits class
superclass . List slotnamelist
contains the names of the additional slots defined by the new class.
List slotdefaultlist contains the
default values for these slots. Both lists are in reverse order (i.e.
the first slot in the list appears last when pretty-printing the class).
This function does not set the value of symbol
classname , use the macro function
defclass for that purpose.
3.10.3.2. (classname c)
|
[DX] |
Returns the name of class c , i.e the
symbol with the corresponding value that was set by
defclass .
Example:
? (classname rect)
= rect
Returns the list of the slots defined for class c
.
Example:
? (slots rect)
= (width height)
? (slots namedrect)
= ((name "noname"))
3.10.3.4. (methods c)
|
[DX] |
Returns the list of all method names defined for class
c .
Returns the superclass of class c or
the empty list if c has no superclass.
Example:
? (super rect)
= ::class:object
? (classname (super namedrect))
= rect
3.10.3.6. (subclasses c)
|
[DX] |
Returns the list of all subclasses of class c
. When argument c is the empty list
subclasses returns the list of root classes, i.e. classes
without superclass.
Example:
(subclasses object)
3.10.4.0. (new class ... args ...)
|
[DY] |
Creates a new instance of a subclass class
of the class object .
If no constructor method is defined no arguments are allowed. If a
constructor method is defined for class class
a construction message is sent to the new object with arguments
args .
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Creates instances of classes <rect> and <namedrect>.
? (setq r (new rect))
= ::rect:06fa0
? (setq nr (new namedrect))
= ::namedrect:06fe8
This function only works when creating instances of subclasses of class
object . It is not possible to directly create instances of
subclasses of other predefined classes.
3.10.4.1. (new-empty class)
|
[DX] |
Creates a new instance of class class
without calling the constructor. All slots are initialized to
() .
Use this function with care because the empty object might trump the
expectations of other code working with this class.
3.10.4.2. (new-copy object)
|
[DX] |
Creates a copy of the user defined object object
. The copy is an instance of the same class with all slots initialized
to the same values. The contents of the slots are not copied. This is
equivalent to:
(let* ((c (classof object))
(n (new-empty c)) )
(setq :n:slot1 :object:slot1)
(setq :n:slot2 :object:slot2)
...
(setq :n:slotN :object:slotN)
n )
Use this function with care because other code working with this class
might not be able to deal with multiple copies of the same object. Calls
to destructors are particularly problematic.
3.10.4.3. (delete x)
|
[DX] |
Deletes the Lush object x .
The operation of this function is somewhat tricky because all other
references to object x must be
converted to references to the empty list.
If destructor methods are defined for an object then destruction
messages are sent. Object x is then
converted to an instance of the class |ZOMBIE|
. During its normal operation, the interpreter recognizes these zombies
and always replaces a reference to a zombie by a reference to the empty
list.
3.10.4.4. (classof x)
|
[DX] |
Returns the class of an object x .
Example:
(classof (new object))
3.10.4.5. (is-of-class x class)
|
[DX] |
Tests if the class of object x of any
of its superclass is equal to class class
.
Example:
? (is-of-class nr rect)
= t
There are various ways to read or change the values stored in the slots
of an object. Changing the value stored in a slot changes the object in
a way comparable to rplaca and
rplacd , in the case of lists. This change will be reflected
through all pointers referring to the same object.
See: (== n1
n2 )
3.10.5.0. :obj:slot1...:slotn
|
[DMC] (sysenv.lsh) |
See: (scope obj
slot1 ... slotn )
See: (scope symb )
This macro character is expanded as a call to the
scope function.
3.10.5.1. (scope obj slot1 ... slotn)
|
[DY] |
See: : obj :
slot1 ...: slotn
See: (scope symb )
The simplest method for setting or getting the slots of an object is
called the scope macro . The syntax
:obj:slot refers to the slot slot
of object obj . Actually, the scope
macro character converts expression :obj:slot
into a list (scope obj slot) .
When this list is evaluated the scope
function returns the value of slot slot
of object obj . Moreover, most
functions that affect the value of a symbol recognize such a list as a
reference to slot slot of object
obj .
Nested scope macros are allowed:
:obj:slot_1:slot2 refers to slot slot2
of the object contained in slot slot1
of object obj .
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
? (setq :nr:name "myrectangle")
= "myrectangle"
? (setq :nr:width 8
:nr:height 6 )
= 6
? (print :nr:width :nr:height :nr:name)
8 6 "myrectangle"
= "myrectangle"
3.10.5.2. (scope symb)
|
[DY] |
See: (scope obj
slot1 ... slotn )
See: : obj :
slot1 ...: slotn
The scope macro has another important use as the unary scope macro
. Expression :symb is converted into
list (scope symb) which refers to the
global value of symbol symb .
Example:
? (defvar x 3)
= 3
? (let ((x 8))
(print :x)
(setq :x 6)
(print x) )
3
8
= 8
? x
= 6
3.10.5.3. (letslot [class] obj l1 ... ln)
|
[DY] |
See: (scope obj
slot1 ... slotn )
See: this
Calls function progn on
l1 ... ln , within the
scope of object obj , and returns the
last result. Within the object scope each slot of the object, either
defined by its class or inherited from its superclasses, can be directly
accessed as the value of its symbolic slot name.
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
? (setq width ())
= ()
? (letslot r
(setq width 4)
(setq height 5) )
= 5
? width
= ()
? (letslot r (* width height))
= 20
Within an object scope the symbol this
always refers to object itself.
The optional argument class must be
the object class or one of its superclasses. The only visible slots are
then defined by class class and its
superclasses. This can make a difference when obj
is an instance of a subclass of class
.
3.10.6.0. (defmethod class symb args . body)
|
[DM] (sysenv.lsh) |
See: Argument List
See: (==> obj
symb ... args ... )
Defines a method named symb for class
class . Argument symb must
be a symbol and is not evaluated. Argument args
must be a valid argument list.
When an instance of class class
receives a message whose selector is symb
the body body of the method is
executed with a call to function progn
. During this execution the slots defined by
class and its superclasses are bound to their symbolic names,
as in letslot , and the arguments of
the message are evaluated and bound to the symbols in argumentlist
args .
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
;;
;; This is a method for computing the surface of a rect.
? (defmethod rect surface()
(* width height) )
= surface
;; a method for printing n times the name of a namedrect
? (defmethod namedrect showname(n)
(repeat n (print name)) )
= showname
3.10.6.1. (demethod class symb args . body)
|
[DM] (sysenv.lsh) |
Identical to defmethod .
3.10.6.2. (dfmethod class symb args . body)
|
[DM] (sysenv.lsh) |
Defines an flambda-method named symb
for class class . flambda-methods do
not evaluate their arguments, unlike regular methods defined with
demethod or defmethod.
3.10.6.3. (dmmethod class symb args . body)
|
[DM] (sysenv.lsh) |
Defines an mlambda-method named symb
for class class . mlambda-methods are
to regular methods what macros (defined with dm
or mlambda ) are to regular functions
(defined with de or
lambda ).
3.10.6.4. (putmethod class symb func)
|
[DX] |
Add method symb to class
class . func must be a
lambda, flmabda, or mlambda.
3.10.6.5. (pretty-method class symb)
|
[DE] (sysenv.lsh) |
Prints a nicely indented definition of method
symb of class class .
3.10.7.0. (==> obj symb ... args ... )
|
[MSG] |
Sends a message whose selector is symb
to object obj , with arguments
args .
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
;; Method <surface> is defined as an example for <defmethod>.
;;
;; Send a surface message to rect <r>
? (==> r surface)
= 20
;; Send a showname message to namedrect <nr>
? (==> nr showname 2)
"myrectangle"
"myrectangle"
= "myrectangle"
;; Send a surface message to namedrect <nr>
;; The method is inherited from superclass <rect>
? (==> nr surface)
= 48
When an object receives a message its method is executed in the object
scope defined by the class that owns the method: If the method is
defined by a superclass only the slots of that superclass and of its
superclasses are directly referred to by their names.
When no method symbol is defined in
the class or superclasses a method named -unknown
is searched for. Once found, the -unknown
method is executed with two arguments: the initial method name
symb and the list of the evaluated arguments
args . An error occurs if method
-unknown is not defined.
3.10.7.1. (==> obj (class . symb) ... args ... )
|
[MSG] |
This construction is known as a cast-and-send . A message with
selector symb and arguments
args is sent to the object obj
, considered as an instance of class class
. Methods are searched for in class class
and its superclasses, instead of the class of obj
and its superclasses.
Argument class is evaluated and must
return a superclass of the class of obj
. Argument symb is not evaluated and
must be a valid method selector for class class
.
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
;; Method <surface> is defined as an example for <defmethod>.
;;
;; Override surface method of class rect
? (defmethod namedrect surface()
;; prints the name by sending a showname message
(==> this showname 1)
;; returns 1+ the result of the surface method of class rect
(1+ (==> this (rect . surface))) )
= surface
? (==> nr surface)
"myrectangle"
= 49
;; Still call the surface method of class rect
? (==> nr (rect . surface))
= 48
See: (letslot obj
l1 ... ln )
See: (==> obj
symb ... args ... )
While Lush is executing a method you can use symbol
this to refer to the object receiving the message.
3.10.7.3. (check==> class symb)
|
[DX] |
Searches class class and its
superclasses for a method whose selector is symb
. If a matching method exists this function returns the method as a DF
function.
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
;; Method <surface> is defined as an example for <defmethod>.
;;
;; There is no method yoyo in rect
? (check==> rect 'yoyo)
= ()
;; there is a method surface in rect
? (check==> rect 'surface)
= DF:0604c
3.10.7.4. (apply==> obj symbol args)
|
[DX] |
Sends message symbol to object
obj with the list args as
arguments.
3.10.8. Constructors and Destructors
|
|
See: (new class ...
args ...)
See: (delete x )
Constructors are specific methods whose selector is the name of their
class, as returned by the function classname
. Constructors are useful for easy initialization of an object during
its creation.
Whenever a new object is created, with the new
function, a construction message is sent to the new object. The optional
arguments of the new function are sent
as arguments to the construction message.
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Method <surface> is defined as an example for <defmethod>.
;;
;; Define a constructor for class rect
? (defmethod rect rect(w h)
(setq width w)
(setq height h) )
= rect
;; creates a new rectangle
? (setq r (new rect 8 9))
= ::rect:06fb8
;; sends a surface message
? (==> r surface)
= 72
The function new only calls a
constructor when it is defined by the class of the newly created object.
However, constructors can call the constructor method of their
superclass.
Example:
;; defines a constructor for class namedrect
? (defmethod namedrect namedrect(w h n)
;; explicitely calls the constructor of class rect.
(==> this rect w h)
(setq name n) )
Destructors are specific methods whose selector is
-destructor . When an object is deleted all the destructors
of its class and superclasses are successively called. Deletion occurs
when the function delete is called on
an object or when the garbage collection mechanism proves that an object
will no longer be accessed.
Note: Only objects created with function new
receive destruction messages. Numbers, strings, and symbols usually do
not receive such messages.
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
;; Method <surface> is defined as an example for <defmethod>.
;;
;; Defines a destructor for the rect class
? (defmethod rect -destructor()
(printf "rect destructor on %l\n" this) )
= -destructor
;; Defines a destructor for the namedrect class
? (defmethod namedrect -destructor()
(printf "namedrect destructor on %l (%s)\n" this name) )
= -destructor
;; deletes objects r and nr
? (delete r)
rect destructor on ::rect:06fb8
= ()
? r
= ()
? (delete nr)
namedrect destructor on ::namedrect:06fe8 (myrectangle)
rect destructor on ::namedrect:06fe8
= ()
? nr
= ()
Destructors allow objects to perform some housekeeping before they
disappear.
3.10.9. Predefined Methods
|
|
3.10.9.0. (==> obj pname)
|
[MSG] |
See: (pname l )
The function pname returns a string
that describes a lisp object. When executing this function Lush searches
the object for a method pname before
applying the hardcoded defaults. Overriding method
pname lets you redefine how Lush prints certain objects.
Example:
;; Classes <rect> and <namedrect> are defined as examples for <defclass>.
;; Objects <r> and <nr> are defined as examples for <new>.
;; Method <surface> is defined as an example for <defmethod>.
;;
;; Defines a pname function for the rect class
? (defmethod rect pname()
(sprintf "<rectangle %d by %d>" width height) )
= pname
? (new rect 8 6)
= <rectangle 8 by 6>
3.10.9.1. (==> obj print)
|
[MSG] |
See: (prin l1 ...
ln )
When Lush prints an object with function prin
or print it searches for a method
print before applying hardcoded defaults based on function
pname .
It is a good idea to override method print
instead of method pname when large
amounts of text are necessary (e.g. in the case of matrices).
3.10.9.2. (==> obj pprint)
|
[MSG] |
See: (pprin l1 ...
ln )
When Lush prints an atom with function pprin
or pprint it searches for a method
pprint before applying the hardcoded defaults.
3.10.9.3. (==> obj pretty)
|
[MSG] |
See: (pretty f )
Function pretty displays an object by
sending them a message pretty . The
default method pretty defined by class
object displays the slots of the object. Specific
pretty methods are also defined for functions, symbols,
classes, and so forth.
3.10.9.4. (==> obj -destructor)
|
[MSG] |
See: Constructors and Destructors
This method is invoked when the object is destroyed.
3.10.9.5. (==> obj -unknown symb args)
|
[MSG] |
See: Sending Messages
This method is invoked when a message symb
is sent to an object obj whose class
or superclasses do not define a suitable method. Argument
args is the list of message arguments the object is
destroyed. An error message is produced when this method is not defined.
3.10.9.6. (==> obj -call args)
|
[MSG] |
This method is invoked when the object obj
is used like a function as the first element of a list to be evaluated.
Argument args contains the arguments
of the calling form. An error message is produced when this method is
not defined.