1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
<HTML>
<HEAD>
<TITLE>Brief Guide to CLOS: Generic functions and methods</TITLE>
</HEAD>
<BODY>
<A HREF="CLOS-guide-5.html"><IMG SRC="prev.gif" ALT="Previous"></A>
<A HREF="CLOS-guide-7.html"><IMG SRC="next.gif" ALT="Next"></A>
<A HREF="CLOS-guide.html#toc6"><IMG SRC="toc.gif" ALT="Contents"></A>
<HR>
<H2><A NAME="s6">6. Generic functions and methods</A></H2>
<P>Generic function in <CODE>CLOS</CODE> are the closest thing to "messages".
Instead of writing</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
(SEND instance operation-name arg*)
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>you write</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
(operation-name instance arg*)
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>The operations / messages are generic functions -- functions whose
behavior can be defined for instances of particular classes by
defining methods.</P>
<P><CODE>(DEFGENERIC function-name lambda-list)</CODE> can be used to define a generic
function. You don't have to call <CODE>DEFGENERIC</CODE>, however, because
<CODE>DEFMETHOD</CODE>
automatically defines the generic function if it has not been defined
already. On the other hand, it's often a good idea to use <CODE>DEFGENERIC</CODE>
as a declaration that an operation exists and has certain parameters.</P>
<P>Anyway, all of the interesting things happen in methods. A method is
defined by:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
(DEFMETHOD generic-function-name specialized-lambda-list
form*)
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>This may look fairly cryptic, but compare it to <CODE>DEFUN</CODE> described in
a similar way:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
(DEFUN function-name lambda-list form*)
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>A "lambda list" is just a list of formal parameters, plus things like
<CODE>&OPTIONAL</CODE> or <CODE>&REST</CODE>. It's because of such
complications that we say
"lambda-list" instead of "(parameter*)"
when describing the syntax.</P>
<P>[I won't say anything
about <CODE> &OPTIONAL </CODE>,
<CODE>&REST</CODE>, or <CODE>&KEY</CODE> in methods.
The rules are in CLtL2 or the HyperSpec, if you want to know them.]</P>
<P>So a normal function has a lambda list like <CODE>(var1 var2 ...)</CODE>.
A method has one in which each parameter can be "specialized"
to a particular class. So it looks like:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
((var1 class1) (var2 class2) ...)
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>The specializer is optional. Omitting it means that the method
can apply to instances of any class, including classes that were
not defined by <CODE>DEFCLASS</CODE>. For example:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
(defmethod change-subject ((teach teacher) new-subject)
(setf (teacher-subject teach) new-subject))
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Here the new-subject could be any object. If you want to restrict
it, you might do something like:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
(defmethod change-subject ((teach teacher) (new-subject string))
(setf (teacher-subject teach) new-subject))
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Or you could define classes of subjects.</P>
<P>Methods in "classical" object-oriented programming specialize
only one parameter. In <CODE>CLOS</CODE>, you can specialize more than one.
If you do, the method is sometimes called a multi-method.</P>
<P>A method defined for a class <CODE>C</CODE> overrides any method defined
for a superclass of <CODE>C</CODE>. The method for <CODE>C</CODE> is
"more specific"
than the method for the superclass, because <CODE>C</CODE> is more specific
that the classes it inherits from (eg, dog is more specific
than animal).</P>
<P>For multi-methods, the determination of which method is more
specific involves more than one parameter. The parameters
are considered from left to right.</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
(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)
</PRE>
</CODE></BLOCKQUOTE>
</P>
<HR>
<A HREF="CLOS-guide-5.html"><IMG SRC="prev.gif" ALT="Previous"></A>
<A HREF="CLOS-guide-7.html"><IMG SRC="next.gif" ALT="Next"></A>
<A HREF="CLOS-guide.html#toc6"><IMG SRC="toc.gif" ALT="Contents"></A>
</BODY>
</HTML>
|