File: CLOS-guide.sgml

package info (click to toggle)
cmucl 21d-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 45,328 kB
  • sloc: lisp: 378,758; ansic: 30,673; asm: 2,977; sh: 1,417; makefile: 357; csh: 31
file content (634 lines) | stat: -rw-r--r-- 17,597 bytes parent folder | download | duplicates (12)
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
<!doctype linuxdoc system>

<article>

<title>Brief Guide to <tt/CLOS/

<author> Jeff Dalton, University of Edinburgh, &lt;J.Dalton@ed.ac.uk&gt;
         Modified by  Bruno Haible &lt;haible@ma2s2.mathematik.uni-karlsruhe.de&gt;
	  and Peter Van Eynde &lt;s950045@uia.ua.ac.be&gt;

<toc>

<sect>Conventions 

<p>
Think of upper case in things like <tt/DEFCLASS/ as literals -- I
don't mean to imply that actual upper case would be used.  ``Thing*''
means zero or more occurrences of thing; ``thing+'' means one or more.
Curly brackets { and } are used for grouping, as in {a b}+, which
means a b, a b a b, a b a b a b, etc.


CLISP specific note: Before using <tt/CLOS/, you need to 
enter ``(USE-PACKAGE &dquot;CLOS&dquot;)''.

CMUCL specific note: /usr/lib/cmucl/lisp.core should point to 
                     /usr/lib/cmucl/pcl-lisp.core or you could have build
                     a custom image with pcl.


<sect>Defining classes.

<p>
You define a class with <tt/DEFCLASS/ :

<tscreen><verb>
(DEFCLASS class-name (superclass-name*)
  (slot-description*)
  class-option*)
</verb></tscreen>


For simple things, forget about class options.


A slot-description has the form <tt/(slot-name slot-option*)/ , where each
option is a keyword followed by a name, expression, or whatever.  The
most useful slot options are


<descrip>
<tag/:ACCESSOR/function-name
<tag/:INITFORM/expression
<tag/:INITARG/symbol
</descrip>


(Initargs are usually keywords.)


<tt/DEFCLASS/ is similar to <tt/DEFSTRUCT/.  The syntax is a bit different, and
you have more control over what things are called.  For instance,
consider the <tt/DEFSTRUCT/:


<tscreen><verb>
(defstruct person
  (name 'bill)
  (age 10))
</verb></tscreen>


<tt/DEFSTRUCT/ would automatically define slots with expressions to
compute default initial values, access-functions like <tt/PERSON-NAME/
to get and set slot values, and a <tt/MAKE-PERSON/ that took keyword
initialization arguments <tt/(initargs)/ as in


<tscreen><verb>
(make-person :name 'george :age 12)
</verb></tscreen>


A <tt/DEFCLASS/ that provided similar access functions, etc, would be:


<tscreen><verb>
(defclass person ()
  ((name :accessor person-name
         :initform 'bill
         :initarg :name)
   (age :accessor person-age
        :initform 10
        :initarg :age)))
</verb></tscreen>


Note that <tt/DEFCLASS/ lets you control what things are called.  For
instance, you don't have to call the accessor <tt/PERSON-NAME/.  You could
call it <tt/NAME/.


In general, you should pick names that make sense for a group of
related classes rather than rigidly following the <tt/DEFSTRUCT/
conventions.


You do not have to provide all options for every slot.
Maybe you don't want it to be possible to initialize a slot
when calling <tt/MAKE-INSTANCE/ (for which see below).  In that case,
don't provide an <tt/:INITARG/.  Or maybe there isn't a meaningful
default value.  (Perhaps the meaningful values will always be
specified by a subclass.)  In that case, no <tt/:INITFORM/.


Note that classes are objects.  To get the class object from its
name, use <tt/(FIND-CLASS name)/.  Ordinarily, you won't need to do this.


<sect>Instances

<p>
You can make an instance of a class with <tt/MAKE-INSTANCE/.  It's
similar to the <tt/MAKE-x/ functions defined by <tt/DEFSTRUCT/ but lets you
pass the class to instantiate as an argument:


<tscreen><verb>
(MAKE-INSTANCE class {initarg value}*)
</verb></tscreen>

Instead of the class object itself, you can use its name.
For example:


<tscreen><verb>
(make-instance 'person :age 100)
</verb></tscreen>


This person object would have age <tt/100/ and name <tt/BILL/, the default.


It's often a good idea to define your own constructor functions,
rather than call <tt/MAKE-INSTANCE/ directly, because you can hide
implementation details and don't have to use keyword parameters
for everything.  For instance, you might want to define


<tscreen><verb>
(defun make-person (name age)
  (make-instance 'person :name name :age age))
</verb></tscreen>


if you wanted the name and age to be required, positional parameters,
rather than keyword parameters.


The accessor functions can be used to get and set slot values:


<tscreen><verb>
<cl> (setq p1 (make-instance 'person :name 'jill :age 100))
#<person @ #x7bf826> 

<cl> (person-name p1)
jill 

<cl> (person-age p1)
100 

<cl> (setf (person-age p1) 101)
101 

<cl> (person-age p1)
101 
</verb></tscreen>


Note that when you use <tt/DEFCLASS/, the instances are printed using
the <tt/&num;&lt;...&gt;/ notation, rather than 
as <tt/&num;s(person :name jill :age 100)/ .
But you can change the way instances are printed by defining methods
on the generic function <tt/PRINT-OBJECT/.

Slots can also be accessed by name using <tt/(SLOT-VALUE instance slot-name)/:


<tscreen><verb>
<cl> (slot-value p1 'name)
jill 

<cl> (setf (slot-value p1 'name) 'jillian)
jillian 

<cl> (person-name p1)
jillian 
</verb></tscreen>

You can find out various things about an instance by calling
<tt/DESCRIBE/:


<tscreen><verb>
<cl> (describe p1)
#<person @ #x7bf826> is an instance 
 of class #<clos:standard-class person @ #x7ad8ae>:
The following slots have :INSTANCE allocation:
age     101
name    jillian
</verb></tscreen>


<sect>Inheritance of slot options

<p>
The class above had no superclass.  That's why there was a
 <tt/&dquot;()&dquot;/ after
<tt/&dquot;defclass person&dquot;/.  Actually, this means it 
has one superclass: the
class <tt/STANDARD-OBJECT/.

When there are superclasses, a subclass can specify a slot that has
already been specified for a superclass.  When this happens, the
information in slot options has to be combined.  For the slot options
listed above, either the option in the subclass overrides the one in
the superclass or there is a union:

<descrip>
<tag/:ACCESSOR/union
<tag/:INITARG/union
<tag/:INITFORM/overrides
</descrip>

This is what you should expect.  The subclass can <bf/change/ the
default initial value by overriding the <tt/:INITFORM/, and can add
to the initargs and accessors.


However, the &dquot;union&dquot; for accessor is just a consequence of how
generic functions work.  If they can apply to instances of a
class C, they can also apply to instances of subclasses of C.


(Accessor functions are generic.  This may become clearer
once generic functions are discussed, below.)


Here are some subclasses:


<tscreen><verb>
<cl> (defclass teacher (person)
      ((subject :accessor teacher-subject
                :initarg :subject)))
#<clos:standard-class teacher @ #x7cf796> 

#<cl> (defclass maths-teacher (teacher)
       ((subject :initform "Mathematics")))
#<clos:standard-class maths-teacher @ #x7d94be> 

<cl> (setq p2 (make-instance 'maths-teacher
                 :name 'john
                 :age 34))
#<maths-teacher @ #x7dcc66> 

<cl> (describe p2)
#<maths-teacher @ #x7dcc66>; is an instance of
     class #<clos:standard-class maths-teacher @ #x7d94be>:
 The following slots have :INSTANCE allocation:
 age        34
 name       john
 subject    "Mathematics"
</verb></tscreen>


Note that classes print like 
<tt/&num;&lt;clos:standard-class maths-teacher @ &num;x7d94be&gt;/.
The <tt/&num;&lt;...&gt;/ notation usually has the form

<tscreen><verb>
#<class-of-the-object ... more information ...>
</verb></tscreen>

So an instance of maths-teacher prints as 
<tt/&num;&lt;MATHS-TEACHER ...&gt;/.
The notation for the classes above indicates that they are
instances of <tt/STANDARD-CLASS/.  <tt/DEFCLASS/ defines standard classes.
<tt/DEFSTRUCT/ defines structure classes.


<sect>Multiple inheritance

<p>
A class can have more than one superclass.  With single inheritance
(one superclass), it's easy to order the superclasses from most to
least specific.  This is the rule:

<itemize>
<item>Rule 1: Each class is more specific than its superclasses.

In multiple inheritance this is harder.  Suppose we have
<tt/(defclass a (b c) ...)/

Class <tt/A/ is more specific than <tt/B/ or <tt/C/ (for instances of 
<tt/A/), but what if
something (an <tt/:INITFORM/, or a method) is specified by 
<tt/B/ and <tt/C/?  Which
overrides the other?  The rule in <tt/CLOS/ is that the superclasses listed
earlier are more specific than those listed later.  So:

<item>Rule 2: For a given class, superclasses listed earlier are more
        specific than those listed later.

These rules are used to compute a linear order for a class and all its
superclasses, from most specific to least specific.  This order is the
&dquot;class precedence list&dquot; of the class.

The two rules are not always enough to determine a unique order,
however, so <tt/CLOS/ has an algorithm for breaking ties.  This ensures
that all implementations always produce the same order, but it's
usually considered a bad idea for programmers to rely on exactly
what the order is.  If the order for some superclasses is important,
it can be expressed directly in the class definition.
</itemize>

<sect>Generic functions and methods

<p>
Generic function in <tt/CLOS/ are the closest thing to &dquot;messages&dquot;.
Instead of writing

<tscreen><verb>
(SEND instance operation-name arg*)
</verb></tscreen>

you write

<tscreen><verb>
(operation-name instance arg*)
</verb></tscreen>

The operations / messages are generic functions -- functions whose
behavior can be defined for instances of particular classes by
defining methods.

<tt/(DEFGENERIC function-name lambda-list)/ can be used to define a generic
function.  You don't have to call <tt/DEFGENERIC/, however, because 
<tt/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 <tt/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:

<tscreen><verb>
(DEFMETHOD generic-function-name specialized-lambda-list
  form*)
</verb></tscreen>

This may look fairly cryptic, but compare it to <tt/DEFUN/ described in
a similar way:

<tscreen><verb>
(DEFUN function-name lambda-list form*)
</verb></tscreen>

A &dquot;lambda list&dquot; is just a list of formal parameters, plus things like
<tt/&amp;OPTIONAL/ or <tt/&amp;REST/.  It's because of such 
complications that we say
&dquot;lambda-list&dquot; instead of &dquot;(parameter*)&dquot; 
when describing the syntax.

&lsqb;I won't say anything 
about <tt> &amp;OPTIONAL </tt>, 
<tt/&amp;REST/, or <tt/&amp;KEY/ in methods.
The rules are in CLtL2 or the HyperSpec, if you want to know them.&rsqb;

So a normal function has a lambda list like <tt/(var1 var2 ...)/.
A method has one in which each parameter can be &dquot;specialized&dquot;
to a particular class.  So it looks like:

<tscreen><verb>
((var1 class1) (var2 class2) ...)
</verb></tscreen>

The specializer is optional.  Omitting it means that the method
can apply to instances of any class, including classes that were
not defined by <tt/DEFCLASS/.  For example:

<tscreen><verb>
(defmethod change-subject ((teach teacher) new-subject)
  (setf (teacher-subject teach) new-subject))
</verb></tscreen>

Here the new-subject could be any object.  If you want to restrict
it, you might do something like:

<tscreen><verb>
(defmethod change-subject ((teach teacher) (new-subject string))
  (setf (teacher-subject teach) new-subject))
</verb></tscreen>

Or you could define classes of subjects.

Methods in &dquot;classical&dquot; object-oriented programming specialize
only one parameter.  In <tt/CLOS/, you can specialize more than one.
If you do, the method is sometimes called a multi-method.

A method defined for a class <tt/C/ overrides any method defined
for a superclass of <tt/C/.  The method for <tt/C/ is 
&dquot;more specific&dquot;
than the method for the superclass, because <tt/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.

<tscreen><verb>
(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) 
</verb></tscreen>


<sect>Method combination.

<p>
When more than one class defines a method for a generic function, and
more than one method is applicable to a given set of arguments, the
applicable methods are combined into a single &dquot;effective method&dquot;.
Each individual method definition is then only part of the definition
of the effective method.

One kind of method combination is always supported by <tt/CLOS/.  It is
called standard method combination.  It is also possible to define
new kinds of method combination.  Standard method combination
involves four kinds of methods:

<itemize>
<item>Primary methods form the main body of the effective method.
    Only the most specific primary method is called, but it can
    call the next most specific primary method by calling

<tscreen><verb>
(call-next-method)
</verb></tscreen>

<item> <tt/:BEFORE/ methods are all called before the primary method, with
    the most specific <tt/:BEFORE/ method called first.

<item> <tt/:AFTER/ methods are all called after the primary method, with
    the most specific <tt/:AFTER/ method called last.

<item> <tt/:AROUND/ methods run before the other methods.  As with
    primary methods, only the most specific is called and the
    rest can be invoked by <tt/CALL-NEXT-METHOD/.  When the least
    specific <tt/:AROUND/ method calls <tt/CALL-NEXT-METHOD/, what it
    calls is the combination of <tt/:BEFORE/, <tt/:AFTER/, and primary
    methods.
</itemize>

<tt/:BEFORE/, <tt/:AFTER/, and <tt/:AROUND/ methods are indicated by putting the
corresponding keyword as a qualifier in the method definition.
<tt/:BEFORE/ and <tt/:AFTER/ methods are the easiest to use, and a simple
example will show how they work:

<tscreen><verb>
(defclass food () ())

(defmethod cook :before ((f food))
  (print "A food is about to be cooked."))

(defmethod cook :after ((f food))
  (print "A food has been cooked."))

(defclass pie (food)
  ((filling :accessor pie-filling :initarg :filling :initform 'apple)))

(defmethod cook ((p pie))
  (print "Cooking a pie")
  (setf (pie-filling p) (list 'cooked (pie-filling p))))

(defmethod cook :before ((p pie))
  (print "A pie is about to be cooked."))

(defmethod cook :after ((p pie))
  (print "A pie has been cooked."))

(setq pie-1 (make-instance 'pie :filling 'apple))
</verb></tscreen>

And now:

<tscreen><verb>
<cl> (cook pie-1)
"A pie is about to be cooked."
"A food is about to be cooked." 
"Cooking a pie"
"A food has been cooked."
"A pie has been cooked."
(cooked apple)
</verb></tscreen>


<sect>Quick reference

<p>
Square brackets (&dquot;&lsqb;&dquot; and &dquot;&rsqb;&dquot;) indicate optional elements.  A vertical
bar (&dquot;&verbar;&dquot;) indicates an alternative.  Thing* means zero or more
occurrence of thing, thing+ means one or more occurrence.  &dquot;{&dquot; and &dquot;}&dquot;
are used for grouping.

<sect1>Defining a class

<p>
<tscreen><verb>
(DEFCLASS class-name (superclass-name*)
  (slot-description*))
</verb></tscreen>

<sect1>Slot descriptions

<p>
<tt/(slot-name slot-option*)/
<descrip>
<tag/:ACCESSOR/function-name
<tag/:INITFORM/expression
<tag/:INITARG/keyword-symbol
</descrip>

<sect1>Making instances

<p>
<tt/(MAKE-INSTANCE class {initarg value}*)/

<sect1>Method definitions

<p>
<tt/
(DEFMETHOD generic-function-name &lsqb;qualifier&rsqb; specialized-lambda-list
  form*)/
where
<itemize>
<item>   generic-function-name is a symbol
<item>   qualifier is :BEFORE, :AFTER, :AROUND, or else omitted
<item>   specialized-lambda-list is 
( {variable &verbar; (variable class-name)}* )
</itemize>

<sect1>Some functions

<p>
<sect2>(DESCRIBE instance)
<sect2>(DESCRIBE class)

<sect2>(FIND-CLASS class-name) -&gt;  class
<p>
As in:
<tscreen><verb>
<cl> (FIND-CLASS 'teacher)

#<STANDARD-CLASS TEACHER {90374C5}>
</verb></tscreen>

<sect2>(CLASS-NAME class) -&gt; symbol
<p>
As in:
<tscreen><verb>
<cl> (class-name (find-class 'teacher))

TEACHER
</verb></tscreen>

<sect2>(CLASS-PRECEDENCE-LIST class) -&gt; list of classes
<p>
&lsqb;This is called <tt/(CLOS::CLASS-PRECEDENCE-LIST class)/ in CLISP.&rsqb;

&lsqb;This is called <tt/(PCL:CLASS-PRECEDENCE-LIST class)/ in CMUCL.&rsqb;

As in (CMUCL):
<tscreen><verb>
* (pcl:class-precedence-list  (find-class 'teacher))

(#<Standard-Class TEACHER {902FF6D}> #<Standard-Class PERSON {9010ADD}>
 #<Standard-Class STANDARD-OBJECT {56753B5}>
 #<Slot-Class PCL::SLOT-OBJECT {567545D}> #<Built-In-Class INSTANCE {567BDDD}>
 #<Built-In-Class T {567B68D}>)
</verb></tscreen>


<sect2>(CLASS-DIRECT-SUPERCLASSES class) -&gt; list of classes

<p>
&lsqb;This is called <tt/(CLOS::CLASS-DIRECT-SUPERCLASSES/ class) in CLISP.&rsqb;

&lsqb;This is called <tt/(PCL:CLASS-DIRECT-SUPERCLASSES/ class) in CMU.&rsqb;

As in (CMUCL):
<tscreen><verb>
* (pcl:class-direct-superclasses (find-class 'teacher))

(#<Standard-Class PERSON {9010ADD}>)
</verb></tscreen>

<sect2>(CLASS-DIRECT-SUBCLASSES class) -&gt; list of classes

<p>
&lsqb;This isn't available in CLISP.&rsqb;

&lsqb;This is called <tt/(PCL:CLASS-DIRECT-SUBCLASSES/ class) in CMU.&rsqb;

As in:
<tscreen><verb>
* (pcl:class-direct-subclasses (find-class 'teacher))

(#<Standard-Class MATHS-TEACHER {9040E9D}>)
</verb></tscreen>

</article>