Generic function in CLOS
are the closest thing to "messages".
Instead of writing
(SEND instance operation-name arg*)
you write
(operation-name instance arg*)
The operations / messages are generic functions -- functions whose behavior can be defined for instances of particular classes by defining methods.
(DEFGENERIC function-name lambda-list)
can be used to define a generic
function. You don't have to call DEFGENERIC
, however, because
DEFMETHOD
automatically defines the generic function if it has not been defined
already. On the other hand, it's often a good idea to use DEFGENERIC
as a declaration that an operation exists and has certain parameters.
Anyway, all of the interesting things happen in methods. A method is defined by:
(DEFMETHOD generic-function-name specialized-lambda-list
form*)
This may look fairly cryptic, but compare it to DEFUN
described in
a similar way:
(DEFUN function-name lambda-list form*)
A "lambda list" is just a list of formal parameters, plus things like
&OPTIONAL
or &REST
. It's because of such
complications that we say
"lambda-list" instead of "(parameter*)"
when describing the syntax.
[I won't say anything
about &OPTIONAL
,
&REST
, or &KEY
in methods.
The rules are in CLtL2 or the HyperSpec, if you want to know them.]
So a normal function has a lambda list like (var1 var2 ...)
.
A method has one in which each parameter can be "specialized"
to a particular class. So it looks like:
((var1 class1) (var2 class2) ...)
The specializer is optional. Omitting it means that the method
can apply to instances of any class, including classes that were
not defined by DEFCLASS
. For example:
(defmethod change-subject ((teach teacher) new-subject)
(setf (teacher-subject teach) new-subject))
Here the new-subject could be any object. If you want to restrict it, you might do something like:
(defmethod change-subject ((teach teacher) (new-subject string))
(setf (teacher-subject teach) new-subject))
Or you could define classes of subjects.
Methods in "classical" object-oriented programming specialize
only one parameter. In CLOS
, you can specialize more than one.
If you do, the method is sometimes called a multi-method.
A method defined for a class C
overrides any method defined
for a superclass of C
. The method for C
is
"more specific"
than the method for the superclass, because C
is more specific
that the classes it inherits from (eg, dog is more specific
than animal).
For multi-methods, the determination of which method is more specific involves more than one parameter. The parameters are considered from left to right.
(defmethod test ((x number) (y number))
'(num num))
(defmethod test ((i integer) (y number))
'(int num))
(defmethod test ((x number) (j integer))
'(num int))
(test 1 1) => (int num), not (num int)
(test 1 1/2) => (int num)
(test 1/2 1) => (num int)
(test 1/2 1/2) => (num num)