chiark / gitweb /
src/class-finalize-impl.lisp (clos-cpl, dylan-cpl): Improve formatting.
[sod] / src / class-finalize-impl.lisp
CommitLineData
abdf50aa
MW
1;;; -*-lisp-*-
2;;;
dea4d055 3;;; Class finalization implementation
abdf50aa
MW
4;;;
5;;; (c) 2009 Straylight/Edgeware
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
e0808c47 10;;; This file is part of the Sensible Object Design, an object system for C.
abdf50aa
MW
11;;;
12;;; SOD is free software; you can redistribute it and/or modify
13;;; it under the terms of the GNU General Public License as published by
14;;; the Free Software Foundation; either version 2 of the License, or
15;;; (at your option) any later version.
16;;;
17;;; SOD is distributed in the hope that it will be useful,
18;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;;; GNU General Public License for more details.
21;;;
22;;; You should have received a copy of the GNU General Public License
23;;; along with SOD; if not, write to the Free Software Foundation,
24;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26(cl:in-package #:sod)
27
28;;;--------------------------------------------------------------------------
dea4d055 29;;; Class precedence lists.
abdf50aa 30
dea4d055
MW
31;; Just for fun, we implement a wide selection of precedence list algorithms.
32;; C3 seems to be clearly the best, with fewer sharp edges for the unwary.
abdf50aa
MW
33;;
34;; The extended precedence graph (EPG) is constructed by adding edges to the
35;; superclass graph. If A and B are classes, then write A < B if A is a
36;; (maybe indirect) subclass of B. For every two classes A and B, and for
37;; every /maximal/ subclass of both A and B (i.e., every C for which C < A
38;; and C < B, but there does not exist D such that D < A, D < B and C < D):
39;; if A precedes B in C's direct superclass list, then draw an edge A -> B,
40;; otherwise draw the edge B -> A.
41;;
42;; A linearization respects the EPG if, whenever A precedes B in the
43;; linearization, there is a path from A to B. The EPG can be cyclic; in
44;; that case, we don't care which order the classes in the cycle are
45;; linearized.
46;;
47;; See Barrett, Cassels, Haahr, Moon, Playford, Withington, `A Monotonic
48;; Superclass Linearization for Dylan' for more detail.
49;; http://www.webcom.com/haahr/dylan/linearization-oopsla96.html
50
e2838dc5
MW
51;;; Utilities.
52
53(export 'merge-class-lists)
54(defun merge-class-lists (lists pick)
55 "Merge the LISTS of classes, using PICK to break ties.
56
57 This is a convenience wrapper around the main `merge-lists' function.
58 Given that class linearizations (almost?) always specify a custom
c05a4977
MW
59 tiebreaker function, this isn't a keyword argument."
60 (merge-lists lists :pick pick))
e2838dc5 61
dea4d055
MW
62;;; Tiebreaker functions.
63
abdf50aa
MW
64(defun clos-tiebreaker (candidates so-far)
65 "The CLOS linearization tiebreaker function.
66
bf090e02
MW
67 Intended for use with `merge-lists'. Returns the member of CANDIDATES
68 which has a direct subclass furthest to the right in the list SO-FAR.
abdf50aa
MW
69
70 This must disambiguate. The SO-FAR list cannot be empty, since the class
71 under construction precedes all of the others. If two classes share a
72 direct subclass then that subclass's direct superclasses list must order
73 them relative to each other."
74
566c6a6a
MW
75 (dolist (class so-far)
76 (dolist (candidate candidates)
77 (when (member candidate (sod-class-direct-superclasses class))
78 (return-from clos-tiebreaker candidate))))
79 (error "SOD INTERNAL ERROR: Failed to break tie in CLOS"))
abdf50aa 80
dea4d055
MW
81(defun c3-tiebreaker (candidates cpls)
82 "The C3 linearization tiebreaker function.
83
bf090e02
MW
84 Intended for use with `merge-lists'. Returns the member of CANDIDATES
85 which appears in the earliest element of CPLS, which should be the list of
86 the class precedence lists of the direct superclasses of the class in
dea4d055
MW
87 question, in the order specified in the class declaration.
88
89 The only class in the class precedence list which does not appear in one
90 of these lists is the new class itself, which must precede all of the
91 others.
92
93 This must disambiguate, since if two classes are in the same class
94 precedence list, then one must appear in it before the other, which
95 provides an ordering between them. (In this situation we return the one
96 that matches earliest anyway, which would still give the right answer.)
97
98 Note that this will merge the CPLs of superclasses /as they are/, not
99 necessarily as C3 would have computed them. This ensures monotonicity
100 assuming that the superclass CPLs are already monotonic. If they aren't,
101 you're going to lose anyway."
102
103 (dolist (cpl cpls)
104 (dolist (candidate candidates)
105 (when (member candidate cpl)
106 (return-from c3-tiebreaker candidate))))
a1985b3c 107 (error "SOD INTERNAL ERROR: Failed to break tie in C3"))
dea4d055
MW
108
109;;; Linearization functions.
110
11e41ddf 111(export 'clos-cpl)
abdf50aa
MW
112(defun clos-cpl (class)
113 "Compute the class precedence list of CLASS using CLOS linearization rules.
114
115 We merge the direct-superclass lists of all of CLASS's superclasses,
bf090e02 116 disambiguating using `clos-tiebreaker'.
abdf50aa
MW
117
118 The CLOS linearization preserves local class ordering, but is not
119 monotonic, and does not respect the extended precedence graph. CLOS
120 linearization will succeed whenever Dylan or C3 linearization succeeds;
121 the converse is not true."
122
123 (labels ((superclasses (class)
124 (let ((direct-supers (sod-class-direct-superclasses class)))
125 (remove-duplicates (cons class
1f1d88f5
MW
126 (mappend #'superclasses
127 direct-supers))))))
5d55bdaa
MW
128 (merge-class-lists (mapcar (lambda (c)
129 (cons c (sod-class-direct-superclasses c)))
130 (superclasses class))
131 #'clos-tiebreaker)))
abdf50aa 132
11e41ddf 133(export 'dylan-cpl)
abdf50aa
MW
134(defun dylan-cpl (class)
135 "Compute the class precedence list of CLASS using Dylan linearization
136 rules.
137
138 We merge the direct-superclass list of CLASS with the full class
139 precedence lists of its direct superclasses, disambiguating using
bf090e02 140 `clos-tiebreaker'. (Inductively, these lists will be consistent with the
abdf50aa
MW
141 CPLs of indirect superclasses, since those CPLs' orderings are reflected
142 in the CPLs of the direct superclasses.)
143
144 The Dylan linearization preserves local class ordering and is monotonic,
145 but does not respect the extended precedence graph.
146
147 Note that this will merge the CPLs of superclasses /as they are/, not
148 necessarily as Dylan would have computed them. This ensures monotonicity
149 assuming that the superclass CPLs are already monotonic. If they aren't,
150 you're going to lose anyway."
151
5d55bdaa
MW
152 (let* ((direct-supers (sod-class-direct-superclasses class))
153 (cpls (mapcar #'sod-class-precedence-list direct-supers)))
154 (merge-class-lists (cons (cons class direct-supers) cpls)
155 #'clos-tiebreaker)))
abdf50aa 156
11e41ddf 157(export 'c3-cpl)
abdf50aa
MW
158(defun c3-cpl (class)
159 "Compute the class precedence list of CLASS using C3 linearization rules.
160
161 We merge the direct-superclass list of CLASS with the full class
162 precedence lists of its direct superclasses, disambiguating using
bf090e02 163 `c3-tiebreaker'.
abdf50aa
MW
164
165 The C3 linearization preserves local class ordering, is monotonic, and
166 respects the extended precedence graph. It is the linearization used in
167 Python, Perl 6 and other languages. It is the recommended linearization
168 for SOD."
169
170 (let* ((direct-supers (sod-class-direct-superclasses class))
171 (cpls (mapcar #'sod-class-precedence-list direct-supers)))
e2838dc5
MW
172 (merge-class-lists (cons (cons class direct-supers) cpls)
173 (lambda (candidates so-far)
abdf50aa
MW
174 (declare (ignore so-far))
175 (c3-tiebreaker candidates cpls)))))
176
11e41ddf 177(export 'flavors-cpl)
abdf50aa
MW
178(defun flavors-cpl (class)
179 "Compute the class precedence list of CLASS using Flavors linearization
180 rules.
181
182 We do a depth-first traversal of the superclass graph, ignoring duplicates
183 of classes we've already visited. Interestingly, this has the property of
184 being able to tolerate cyclic superclass graphs, though defining cyclic
185 graphs is syntactically impossible in SOD.
186
187 This linearization has few other redeeming features, however. In
188 particular, the top class tends not to be at the end of the CPL, despite
189 it being unequivocally less specific than any other class."
190
191 (let ((done nil))
192 (labels ((walk (class)
193 (unless (member class done)
194 (push class done)
195 (dolist (super (sod-class-direct-superclasses class))
196 (walk super)))))
197 (walk class)
198 (nreverse done))))
199
11e41ddf 200(export 'python-cpl)
abdf50aa
MW
201(defun python-cpl (class)
202 "Compute the class precedence list of CLASS using the documented Python 2.2
203 linearization rules.
204
205 We do a depth-first traversal of the superclass graph, retaining only the
206 last occurrence of each class visited.
207
208 This linearization has few redeeming features. It was never actually
209 implemented; the true Python 2.2 linearization seems closer to (but
210 different from) L*LOOPS."
211
212 (let ((done nil))
213 (labels ((walk (class)
214 (push class done)
215 (dolist (super (sod-class-direct-superclasses class))
216 (walk super))))
217 (walk class)
218 (delete-duplicates (nreverse done)))))
219
11e41ddf 220(export 'l*loops-cpl)
abdf50aa
MW
221(defun l*loops-cpl (class)
222 "Compute the class precedence list of CLASS using L*LOOPS linearization
223 rules.
224
225 We merge the class precedence lists of the direct superclasses of CLASS,
226 disambiguating by choosing the earliest candidate which appears in a
227 depth-first walk of the superclass graph.
228
229 The L*LOOPS rules are monotonic and respect the extended precedence
230 graph. However (unlike Dylan and CLOS) they don't respect local
231 precedence order i.e., the direct-superclasses list orderings."
232
233 (let ((dfs (flavors-cpl class)))
e2838dc5
MW
234 (cons class
235 (merge-class-lists (mapcar #'sod-class-precedence-list
abdf50aa 236 (sod-class-direct-superclasses class))
e2838dc5
MW
237 (lambda (candidates so-far)
238 (declare (ignore so-far))
239 (dolist (class dfs)
240 (when (member class candidates)
241 (return class))))))))
abdf50aa 242
dea4d055 243;;; Default function.
abdf50aa
MW
244
245(defmethod compute-cpl ((class sod-class))
246 (handler-case (c3-cpl class)
247 (inconsistent-merge-error ()
248 (error "Failed to compute class precedence list for `~A'"
249 (sod-class-name class)))))
250
251;;;--------------------------------------------------------------------------
dea4d055
MW
252;;; Chains.
253
254(defmethod compute-chains ((class sod-class))
255 (with-default-error-location (class)
256 (with-slots (chain-link class-precedence-list) class
257 (let* ((head (if chain-link
258 (sod-class-chain-head chain-link)
259 class))
260 (chain (cons class (and chain-link
261 (sod-class-chain chain-link))))
ab7e7521 262 (state (make-inheritance-path-reporter-state class))
dea4d055
MW
263 (table (make-hash-table)))
264
265 ;; Check the chains. We work through each superclass, maintaining a
266 ;; hash table keyed by class. If we encounter a class C which links
267 ;; to L, then we store C as L's value; if L already has a value then
268 ;; we've found an error. By the end of all of this, the classes
269 ;; which don't have an entry are the chain tails.
270 (dolist (super class-precedence-list)
ab7e7521
MW
271 (let* ((link (sod-class-chain-link super))
272 (found (and link (gethash link table))))
273 (cond ((not found) (setf (gethash link table) super))
274 (t
275 (cerror* "Conflicting chains in class `~A': ~
276 (`~A' and `~A' both link to `~A')"
277 class super found link)
278 (report-inheritance-path state super)
279 (report-inheritance-path state found)))))
dea4d055
MW
280
281 ;; Done.
282 (values head chain
283 (cons chain
284 (mapcar #'sod-class-chain
285 (remove-if (lambda (super)
286 (gethash super table))
287 (cdr class-precedence-list)))))))))
288
981b6fb6
MW
289;;;--------------------------------------------------------------------------
290;;; Metaclasses.
291
981b6fb6
MW
292(defmethod guess-metaclass ((class sod-class))
293 "Default metaclass-guessing function for classes.
294
295 Return the most specific metaclass of any of the CLASS's direct
296 superclasses."
297
298 ;; During bootstrapping, our superclasses might not have their own
299 ;; metaclasses resolved yet. If we find this, then throw `bootstrapping'
300 ;; so that `shared-initialize' on `sod-class' can catch it (or as a shot
301 ;; across the bows of anyone else who calls us).
e45a106d
MW
302 (finalization-error (:bad-metaclass)
303 (select-minimal-class-property (sod-class-direct-superclasses class)
304 (lambda (super)
305 (if (slot-boundp super 'metaclass)
306 (slot-value super 'metaclass)
307 (throw 'bootstrapping nil)))
308 #'sod-subclass-p class "metaclass")))
981b6fb6 309
dea4d055
MW
310;;;--------------------------------------------------------------------------
311;;; Sanity checking.
312
313(defmethod check-sod-class ((class sod-class))
314 (with-default-error-location (class)
315
316 ;; Check the names of things are valid.
ab7e7521
MW
317 (flet ((check-list (list what namefunc)
318 (dolist (item list)
319 (let ((name (funcall namefunc item)))
320 (unless (valid-name-p name)
321 (cerror*-with-location item
322 "Invalid ~A name `~A' ~
323 in class `~A'"
324 what name class))))))
325 (unless (valid-name-p (sod-class-name class))
326 (cerror* "Invalid class name `~A'" class))
327 (unless (valid-name-p (sod-class-nickname class))
328 (cerror* "Invalid class nickname `~A' for class `~A'"
329 (sod-class-nickname class) class))
330 (check-list (sod-class-messages class) "message" #'sod-message-name)
331 (check-list (sod-class-slots class) "slot" #'sod-slot-name))
332
333 ;; Check that the class doesn't define conflicting things.
334 (labels ((check-list (list keyfunc complain)
335 (let ((seen (make-hash-table :test #'equal)))
dea4d055 336 (dolist (item list)
ab7e7521
MW
337 (let* ((key (funcall keyfunc item))
338 (found (gethash key seen)))
339 (if found (funcall complain item found)
340 (setf (gethash key seen) item))))))
341 (simple-previous (previous)
342 (info-with-location previous "Previous definition was here"))
343 (simple-complain (what namefunc)
344 (lambda (item previous)
345 (cerror*-with-location item
346 "Duplicate ~A `~A' in class `~A'"
347 what (funcall namefunc item) class)
348 (simple-previous previous))))
349
350 ;; Make sure direct slots have distinct names.
351 (check-list (sod-class-slots class) #'sod-slot-name
352 (simple-complain "slot name" #'sod-slot-name))
353
354 ;; Make sure there's at most one initializer for each slot.
355 (flet ((check-initializer-list (list kind)
356 (check-list list #'sod-initializer-slot
357 (lambda (initializer previous)
358 (let ((slot
359 (sod-initializer-slot initializer)))
360 (cerror*-with-location initializer
361 "Duplicate ~
362 initializer for ~
363 ~A slot `~A' ~
364 in class `~A'"
365 kind slot class)
366 (simple-previous previous))))))
367 (check-initializer-list (sod-class-instance-initializers class)
368 "instance")
369 (check-initializer-list (sod-class-class-initializers class)
370 "class"))
371
372 ;; Make sure messages have distinct names.
373 (check-list (sod-class-messages class) #'sod-message-name
374 (simple-complain "message name" #'sod-message-name))
375
376 ;; Make sure methods are sufficiently distinct.
377 (check-list (sod-class-methods class) #'sod-method-function-name
378 (lambda (method previous)
379 (cerror*-with-location method
380 "Duplicate ~A direct method ~
381 for message `~A' ~
382 in classs `~A'"
383 (sod-method-description method)
384 (sod-method-message method)
385 class)
386 (simple-previous previous)))
387
388 ;; Make sure superclasses have distinct nicknames.
389 (let ((state (make-inheritance-path-reporter-state class)))
390 (check-list (sod-class-precedence-list class) #'sod-class-nickname
391 (lambda (super previous)
392 (cerror*-with-location class
393 "Duplicate nickname `~A' ~
394 in superclasses of `~A': ~
395 used by `~A' and `~A'"
396 (sod-class-nickname super)
397 class super previous)
398 (report-inheritance-path state super)
399 (report-inheritance-path state previous)))))
dea4d055
MW
400
401 ;; Check that the CHAIN-TO class is actually a proper superclass. (This
402 ;; eliminates hairy things like a class being its own link.)
ab7e7521
MW
403 (let ((link (sod-class-chain-link class)))
404 (unless (or (not link)
405 (member link (cdr (sod-class-precedence-list class))))
406 (cerror* "In `~A~, chain-to class `~A' is not a proper superclass"
407 class link)))
dea4d055 408
b2983f35
MW
409 ;; Check that the initargs declare compatible types. Duplicate entries,
410 ;; even within a class, are harmless, but at most one initarg in any
411 ;; class should declare a default value.
ab7e7521
MW
412 (let ((seen (make-hash-table :test #'equal))
413 (state (make-inheritance-path-reporter-state class)))
414 (dolist (super (sod-class-precedence-list class))
415 (dolist (initarg (reverse (sod-class-initargs super)))
416 (let* ((initarg-name (sod-initarg-name initarg))
417 (initarg-type (sod-initarg-type initarg))
418 (initarg-default (sod-initarg-default initarg))
419 (found (gethash initarg-name seen))
420 (found-type (and found (sod-initarg-type found)))
421 (found-default (and found (sod-initarg-default found)))
422 (found-class (and found (sod-initarg-class found)))
423 (found-location (and found (file-location found))))
424 (with-default-error-location (initarg)
425 (cond ((not found)
426 (setf (gethash initarg-name seen) initarg))
427 ((not (c-type-equal-p initarg-type found-type))
428 (cerror* "Inititalization argument `~A' defined ~
429 with incompatible types: ~
430 ~A in class `~A', but ~A in class `~A'"
431 initarg-name initarg-type super
432 found-type found-class found-location)
433 (report-inheritance-path state super))
434 ((and initarg-default found-default
435 (eql super found-class))
436 (cerror* "Initialization argument `~A' redefined ~
437 with default value"
438 initarg-name)
439 (info-with-location found-location
440 "Previous definition is here"))
441 (initarg-default
442 (setf (gethash initarg-name seen) initarg))))))))
b2983f35 443
dea4d055
MW
444 ;; Check for circularity in the superclass graph. Since the superclasses
445 ;; should already be acyclic, it suffices to check that our class is not
446 ;; a superclass of any of its own direct superclasses.
447 (let ((circle (find-if (lambda (super)
448 (sod-subclass-p super class))
449 (sod-class-direct-superclasses class))))
450 (when circle
ab7e7521
MW
451 (cerror* "`~A' is already a superclass of `~A'" class circle)
452 (report-inheritance-path (make-inheritance-path-reporter-state class)
453 circle)))
dea4d055
MW
454
455 ;; Check that the class has a unique root superclass.
456 (find-root-superclass class)
457
458 ;; Check that the metaclass is a subclass of each direct superclass's
459 ;; metaclass.
ab7e7521
MW
460 (finalization-error (:bad-metaclass)
461 (let ((meta (sod-class-metaclass class)))
462 (dolist (super (sod-class-direct-superclasses class))
463 (let ((supermeta (sod-class-metaclass super)))
464 (unless (sod-subclass-p meta supermeta)
465 (cerror* "Metaclass `~A' of `~A' isn't a subclass of `~A'"
466 meta class supermeta)
467 (info-with-location super
468 "Direct superclass `~A' defined here ~
469 has metaclass `~A'"
470 super supermeta))))))))
dea4d055
MW
471
472;;;--------------------------------------------------------------------------
473;;; Finalization.
474
32bb097f
MW
475(defmethod finalize-sod-class :around ((class sod-class))
476 "Common functionality for `finalize-sod-class'.
dea4d055 477
32bb097f
MW
478 * If an attempt to finalize the CLASS has been made before, then we
479 don't try again. Similarly, attempts to finalize a class recursively
480 will fail.
dea4d055 481
32bb097f
MW
482 * A condition handler is established to keep track of whether any errors
483 are signalled during finalization. The CLASS is only marked as
484 successfully finalized if no (unhandled) errors are encountered."
dea4d055
MW
485 (with-default-error-location (class)
486 (ecase (sod-class-state class)
487 ((nil)
488
32bb097f 489 ;; If this fails, leave the class marked as a loss.
16f9fb72 490 (setf (slot-value class 'state) :broken)
dea4d055 491
e45a106d
MW
492 ;; Invoke the finalization method proper. If it signals any
493 ;; continuable errors, take note of them so that we can report failure
494 ;; properly.
495 ;;
496 ;; Catch: we get called recursively to clean up superclasses and
497 ;; metaclasses, but there should only be one such handler, so don't
498 ;; add another. (In turn, this means that other methods mustn't
499 ;; actually trap their significant errors.)
500 (let ((have-handler-p (boundp '*finalization-errors*))
501 (*finalization-errors* nil)
502 (*finalization-error-token* nil))
503 (catch '%finalization-failed
504 (if have-handler-p (call-next-method)
505 (handler-bind ((error (lambda (cond)
506 (declare (ignore cond))
507 (pushnew *finalization-error-token*
508 *finalization-errors*
509 :test #'equal)
510 :decline)))
511 (call-next-method)))
512 (when *finalization-errors* (finalization-failed))
513 (setf (slot-value class 'state) :finalized)
514 t)))
dea4d055 515
32bb097f 516 ;; If the class is broken, we're not going to be able to fix it now.
dea4d055
MW
517 (:broken
518 nil)
519
32bb097f 520 ;; If we already finalized it, there's no point doing it again.
dea4d055
MW
521 (:finalized
522 t))))
abdf50aa 523
32bb097f
MW
524(defmethod finalize-sod-class ((class sod-class))
525
526 ;; CLONE-AND-HACK WARNING: Note that `bootstrap-classes' has a (very brief)
527 ;; clone of the CPL and chain establishment code. If the interface changes
528 ;; then `bootstrap-classes' will need to be changed too.
529
530 ;; Set up the metaclass if it's not been set already. This is delayed
531 ;; to give bootstrapping a chance to set up metaclass and superclass
532 ;; circularities.
533 (default-slot (class 'metaclass) (guess-metaclass class))
534
535 ;; Finalize all of the superclasses. There's some special pleading here to
536 ;; make bootstrapping work: we don't try to finalize the metaclass if we're
537 ;; a root class (no direct superclasses -- because in that case the
538 ;; metaclass will have to be a subclass of us!), or if it's equal to us.
e45a106d
MW
539 ;; This is enough to tie the knot at the top of the class graph. If we
540 ;; can't manage this then we're doomed.
541 (flet ((try-finalizing (what other-class)
542 (unless (finalize-sod-class other-class)
543 (cerror* "Class `~A' has broken ~A `~A'" class what other-class)
544 (info-with-location other-class
545 "Class `~A' defined here" other-class)
546 (finalization-failed))))
547 (let ((supers (sod-class-direct-superclasses class))
548 (meta (sod-class-metaclass class)))
549 (dolist (super supers)
550 (try-finalizing "direct superclass" super))
551 (unless (or (null supers) (eq class meta))
552 (try-finalizing "metaclass" meta))))
32bb097f
MW
553
554 ;; Stash the class's type.
555 (setf (slot-value class '%type)
556 (make-class-type (sod-class-name class)))
557
558 ;; Clobber the lists of items if they've not been set.
559 (dolist (slot '(slots instance-initializers class-initializers
560 messages methods))
561 (unless (slot-boundp class slot)
562 (setf (slot-value class slot) nil)))
563
e45a106d
MW
564 ;; If the CPL hasn't been done yet, compute it. If we can't manage this
565 ;; then there's no hope at all.
566 (unless (slot-boundp class 'class-precedence-list)
567 (restart-case
568 (setf (slot-value class 'class-precedence-list) (compute-cpl class))
569 (continue () :report "Continue"
570 (finalization-failed))))
32bb097f
MW
571
572 ;; Check that the class is fairly sane.
573 (check-sod-class class)
574
575 ;; Determine the class's layout.
576 (setf (values (slot-value class 'chain-head)
577 (slot-value class 'chain)
578 (slot-value class 'chains))
579 (compute-chains class)))
580
abdf50aa 581;;;----- That's all, folks --------------------------------------------------