/[cmucl]/src/pcl/std-class.lisp
ViewVC logotype

Contents of /src/pcl/std-class.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations)
Sun Aug 12 03:48:21 1990 UTC (23 years, 8 months ago) by wlott
Branch: MAIN
Branch point for: patch_15
Initial revision
1 ;;;-*-Mode:LISP; Package:PCL; Base:10; Syntax:Common-lisp -*-
2 ;;;
3 ;;; *************************************************************************
4 ;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
5 ;;; All rights reserved.
6 ;;;
7 ;;; Use and copying of this software and preparation of derivative works
8 ;;; based upon this software are permitted. Any distribution of this
9 ;;; software or derivative works must comply with all applicable United
10 ;;; States export control laws.
11 ;;;
12 ;;; This software is made available AS IS, and Xerox Corporation makes no
13 ;;; warranty about the software, its performance or its conformity to any
14 ;;; specification.
15 ;;;
16 ;;; Any person obtaining a copy of this software is requested to send their
17 ;;; name and post office or electronic mail address to:
18 ;;; CommonLoops Coordinator
19 ;;; Xerox PARC
20 ;;; 3333 Coyote Hill Rd.
21 ;;; Palo Alto, CA 94304
22 ;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
23 ;;;
24 ;;; Suggestions, comments and requests for improvements are also welcome.
25 ;;; *************************************************************************
26 ;;;
27
28 (in-package 'pcl)
29
30 (define-gf-predicate classp class)
31 (define-gf-predicate standard-class-p standard-class)
32 (define-gf-predicate forward-referenced-class-p forward-referenced-class)
33
34
35
36 (defmethod shared-initialize :after ((object documentation-mixin)
37 slot-names
38 &key documentation)
39 (declare (ignore slot-names))
40 (setf (plist-value object 'documentation) documentation))
41
42
43 (defmethod documentation (object &optional doc-type)
44 (lisp:documentation object doc-type))
45
46 (defmethod (setf documentation) (new-value object &optional doc-type)
47 (declare (ignore new-value doc-type))
48 (error "Can't change the documentation of ~S." object))
49
50
51 (defmethod documentation ((object documentation-mixin) &optional doc-type)
52 (declare (ignore doc-type))
53 (plist-value object 'documentation))
54
55 (defmethod (setf documentation) (new-value (object documentation-mixin) &optional doc-type)
56 (declare (ignore doc-type))
57 (setf (plist-value object 'documentation) new-value))
58
59
60 (defmethod documentation ((slotd standard-slot-definition) &optional doc-type)
61 (declare (ignore doc-type))
62 (slot-value slotd 'documentation))
63
64 (defmethod (setf documentation) (new-value (slotd standard-slot-definition) &optional doc-type)
65 (declare (ignore doc-type))
66 (setf (slot-value slotd 'documentation) new-value))
67
68
69 ;;;
70 ;;; Various class accessors that are a little more complicated than can be
71 ;;; done with automatically generated reader methods.
72 ;;;
73 (defmethod class-wrapper ((class pcl-class))
74 (with-slots (wrapper) class
75 (let ((w? wrapper))
76 (if (consp w?)
77 (let ((new (make-wrapper class)))
78 (setf (wrapper-instance-slots-layout new) (car w?)
79 (wrapper-class-slots new) (cdr w?))
80 (setq wrapper new))
81 w?))))
82
83 (defmethod class-precedence-list ((class pcl-class))
84 (unless (class-finalized-p class) (finalize-inheritance class))
85 (with-slots (class-precedence-list) class class-precedence-list))
86
87 (defmethod class-finalized-p ((class pcl-class))
88 (with-slots (wrapper) class (not (null wrapper))))
89
90 (defmethod class-prototype ((class std-class))
91 (with-slots (prototype) class
92 (or prototype (setq prototype (allocate-instance class)))))
93
94 (defmethod class-direct-default-initargs ((class std-class))
95 (plist-value class 'direct-default-initargs))
96
97 (defmethod class-default-initargs ((class std-class))
98 (plist-value class 'default-initargs))
99
100 (defmethod class-constructors ((class std-class))
101 (plist-value class 'constructors))
102
103 (defmethod class-slot-cells ((class std-class))
104 (plist-value class 'class-slot-cells))
105
106 (defmethod find-slot-definition ((class std-class) slot-name)
107 (dolist (eslotd (class-slots class))
108 (when (eq (slotd-name eslotd) slot-name) (return eslotd))))
109
110
111 ;;;
112 ;;; Class accessors that are even a little bit more complicated than those
113 ;;; above. These have a protocol for updating them, we must implement that
114 ;;; protocol.
115 ;;;
116
117 ;;;
118 ;;; Maintaining the direct subclasses backpointers. The update methods are
119 ;;; here, the values are read by an automatically generated reader method.
120 ;;;
121 (defmethod add-direct-subclass ((class class) (subclass class))
122 (with-slots (direct-subclasses) class
123 (pushnew subclass direct-subclasses)
124 subclass))
125
126 (defmethod remove-direct-subclass ((class class) (subclass class))
127 (with-slots (direct-subclasses) class
128 (setq direct-subclasses (remove subclass direct-subclasses))
129 subclass))
130
131 ;;;
132 ;;; Maintaining the direct-methods and direct-generic-functions backpointers.
133 ;;;
134 ;;; There are four generic functions involved, each has one method for the
135 ;;; class case and another method for the damned EQL specializers. All of
136 ;;; these are specified methods and appear in their specified place in the
137 ;;; class graph.
138 ;;;
139 ;;; ADD-METHOD-ON-SPECIALIZER
140 ;;; REMOVE-METHOD-ON-SPECIALIZER
141 ;;; SPECIALIZER-METHODS
142 ;;; SPECIALIZER-GENERIC-FUNCTIONS
143 ;;;
144 ;;; In each case, we maintain one value which is a cons. The car is the list
145 ;;; methods. The cdr is a list of the generic functions. The cdr is always
146 ;;; computed lazily.
147 ;;;
148
149 (defmethod add-method-on-specializer ((method method) (specializer class))
150 (with-slots (direct-methods) specializer
151 (setf (car direct-methods) (adjoin method (car direct-methods)) ;PUSH
152 (cdr direct-methods) ()))
153 method)
154
155 (defmethod remove-method-on-specializer ((method method) (specializer class))
156 (with-slots (direct-methods) specializer
157 (setf (car direct-methods) (remove method (car direct-methods))
158 (cdr direct-methods) ()))
159 method)
160
161 (defmethod specializer-methods ((specializer class))
162 (with-slots (direct-methods) specializer
163 (car direct-methods)))
164
165 (defmethod specializer-generic-functions ((specializer class))
166 (with-slots (direct-methods) specializer
167 (or (cdr direct-methods)
168 (setf (cdr direct-methods)
169 (gathering1 (collecting-once)
170 (dolist (m (car direct-methods))
171 (gather1 (method-generic-function m))))))))
172
173
174
175 ;;;
176 ;;; This hash table is used to store the direct methods and direct generic
177 ;;; functions of EQL specializers. Each value in the table is the cons.
178 ;;;
179 (defvar *eql-specializer-methods* (make-hash-table :test #'eql))
180
181 (defmethod add-method-on-specializer ((method method) (specializer eql-specializer))
182 (let* ((object (eql-specializer-object specializer))
183 (entry (gethash object *eql-specializer-methods*)))
184 (unless entry
185 (setq entry
186 (setf (gethash object *eql-specializer-methods*)
187 (cons nil nil))))
188 (setf (car entry) (adjoin method (car entry))
189 (cdr entry) ())
190 method))
191
192 (defmethod remove-method-on-specializer ((method method) (specializer eql-specializer))
193 (let* ((object (eql-specializer-object specializer))
194 (entry (gethash object *eql-specializer-methods*)))
195 (when entry
196 (setf (car entry) (remove method (car entry))
197 (cdr entry) ()))
198 method))
199
200 (defmethod specializer-methods ((specializer eql-specializer))
201 (car (gethash (eql-specializer-object specializer) *eql-specializer-methods*)))
202
203 (defmethod specializer-generic-functions ((specializer eql-specializer))
204 (let* ((object (eql-specializer-object specializer))
205 (entry (gethash object *eql-specializer-methods*)))
206 (when entry
207 (or (cdr entry)
208 (setf (cdr entry)
209 (gathering1 (collecting-once)
210 (dolist (m (car entry))
211 (gather1 (method-generic-function m)))))))))
212
213
214
215 (defun real-load-defclass (name metaclass-name supers slots other accessors)
216 (do-standard-defsetfs-for-defclass accessors) ;***
217 (apply #'ensure-class name :metaclass metaclass-name
218 :direct-superclasses supers
219 :direct-slots slots
220 :definition-source `((defclass ,name)
221 ,(load-truename))
222 other))
223
224 (defun ensure-class (name &rest all)
225 (apply #'ensure-class-using-class name (find-class name nil) all))
226
227 (defmethod ensure-class-using-class (name (class null) &rest args &key)
228 (multiple-value-bind (meta initargs)
229 (ensure-class-values class args)
230 (setf class (apply #'make-instance meta :name name initargs)
231 (find-class name) class)
232 (inform-type-system-about-class class name) ;***
233 class))
234
235 (defmethod ensure-class-using-class (name (class pcl-class) &rest args &key)
236 (multiple-value-bind (meta initargs)
237 (ensure-class-values class args)
238 (unless (eq (class-of class) meta) (change-class class meta))
239 (apply #'reinitialize-instance class initargs)
240 (inform-type-system-about-class class name) ;***
241 class))
242
243 (defun ensure-class-values (class args)
244 (let* ((initargs (copy-list args))
245 (unsupplied (list 1))
246 (supplied-meta (getf initargs :metaclass unsupplied))
247 (supplied-supers (getf initargs :direct-superclasses unsupplied))
248 (supplied-slots (getf initargs :direct-slots unsupplied))
249 (meta
250 (cond ((neq supplied-meta unsupplied)
251 (find-class supplied-meta))
252 ((or (null class)
253 (forward-referenced-class-p class))
254 *the-class-standard-class*)
255 (t
256 (class-of class))))
257 (proto (class-prototype meta)))
258 (flet ((fix-super (s)
259 (cond ((classp s) s)
260 ((not (legal-class-name-p s))
261 (error "~S is not a class or a legal class name." s))
262 (t
263 (or (find-class s nil)
264 (setf (find-class s)
265 (make-instance 'forward-referenced-class
266 :name s)))))))
267 (loop (unless (remf initargs :metaclass) (return)))
268 (loop (unless (remf initargs :direct-superclasses) (return)))
269 (loop (unless (remf initargs :direct-slots) (return)))
270 (values meta
271 (list* :direct-superclasses
272 (and (neq supplied-supers unsupplied)
273 (mapcar #'fix-super supplied-supers))
274 :direct-slots
275 (and (neq supplied-slots unsupplied) supplied-slots)
276 initargs)))))
277
278
279 ;;;
280 ;;;
281 ;;;
282 (defmethod shared-initialize :before ((class std-class)
283 slot-names
284 &key direct-superclasses)
285 (declare (ignore slot-names))
286 ;; *** error checking
287 )
288
289 (defmethod shared-initialize :after
290 ((class std-class)
291 slot-names
292 &key direct-superclasses
293 direct-slots
294 direct-default-initargs)
295 (declare (ignore slot-names))
296 (when (null direct-superclasses)
297 (setq direct-superclasses (list *the-class-standard-object*)))
298 (setq direct-slots
299 (mapcar #'(lambda (pl) (make-direct-slotd class pl)) direct-slots))
300 (setf (slot-value class 'direct-superclasses) direct-superclasses
301 (slot-value class 'direct-slots) direct-slots)
302 (setf (plist-value class 'direct-default-initargs) direct-default-initargs)
303 (setf (plist-value class 'class-slot-cells)
304 (gathering1 (collecting)
305 (dolist (dslotd direct-slots)
306 (when (eq (slotd-allocation dslotd) class)
307 (let ((initfunction (slotd-initfunction dslotd)))
308 (gather1 (cons (slotd-name dslotd)
309 (if initfunction (funcall initfunction) *slot-unbound*))))))))
310 (add-direct-subclasses class direct-superclasses)
311 (add-slot-accessors class direct-slots))
312
313 (defmethod reinitialize-instance :before ((class std-class)
314 &key direct-superclasses
315 direct-slots
316 direct-default-initargs)
317 (declare (ignore direct-default-initargs))
318 (remove-direct-subclasses class direct-superclasses)
319 (remove-slot-accessors class (class-direct-slots class)))
320
321 (defmethod reinitialize-instance :after ((class std-class)
322 &rest initargs
323 &key)
324 (update-class class nil)
325 (map-dependents class
326 #'(lambda (dependent)
327 (apply #'update-dependent class dependent initargs))))
328
329 (defun add-slot-accessors (class dslotds)
330 (fix-slot-accessors class dslotds 'add))
331
332 (defun remove-slot-accessors (class dslotds)
333 (fix-slot-accessors class dslotds 'remove))
334
335 (defun fix-slot-accessors (class dslotds add/remove)
336 (flet ((fix (gfspec name r/w)
337 (let ((gf (ensure-generic-function gfspec)))
338 (case r/w
339 (r (if (eq add/remove 'add)
340 (add-reader-method class gf name)
341 (remove-reader-method class gf)))
342 (w (if (eq add/remove 'add)
343 (add-writer-method class gf name)
344 (remove-writer-method class gf)))))))
345 (dolist (dslotd dslotds)
346 (let ((slot-name (slotd-name dslotd)))
347 (dolist (r (slotd-readers dslotd)) (fix r slot-name 'r))
348 (dolist (w (slotd-writers dslotd)) (fix w slot-name 'w))))))
349
350
351 (defun add-direct-subclasses (class new)
352 (dolist (n new)
353 (unless (memq class (class-direct-subclasses class))
354 (add-direct-subclass n class))))
355
356 (defun remove-direct-subclasses (class new)
357 (let ((old (class-direct-superclasses class)))
358 (dolist (o (set-difference old new))
359 (remove-direct-subclass o class))))
360
361
362 ;;;
363 ;;;
364 ;;;
365 (defmethod finalize-inheritance ((class std-class))
366 (update-class class t))
367
368
369 ;;;
370 ;;; Called by :after reinitialize instance whenever a class is reinitialized.
371 ;;; The class may or may not be finalized.
372 ;;;
373 (defun update-class (class finalizep)
374 (when (or finalizep (class-finalized-p class))
375 (let* ((dsupers (class-direct-superclasses class))
376 (dslotds (class-direct-slots class))
377 (dinits (class-direct-default-initargs class))
378 (cpl (compute-class-precedence-list class dsupers))
379 (eslotds (compute-slots class cpl dslotds))
380 (inits (compute-default-initargs class cpl dinits)))
381
382 (update-cpl class cpl)
383 (update-slots class cpl eslotds)
384 (update-inits class inits)
385 (update-constructors class)))
386 (unless finalizep
387 (dolist (sub (class-direct-subclasses class)) (update-class sub nil))))
388
389 (defun update-cpl (class cpl)
390 (when (class-finalized-p class)
391 (unless (equal (class-precedence-list class) cpl)
392 (force-cache-flushes class)))
393 (setf (slot-value class 'class-precedence-list) cpl))
394
395 (defun update-slots (class cpl eslotds)
396 (multiple-value-bind (nlayout nwrapper-class-slots)
397 (compute-storage-info cpl eslotds)
398 ;;
399 ;; If there is a change in the shape of the instances then the
400 ;; old class is now obsolete.
401 ;;
402 (let* ((owrapper (class-wrapper class))
403 (olayout (and owrapper (wrapper-instance-slots-layout owrapper)))
404 (owrapper-class-slots (and owrapper (wrapper-class-slots owrapper)))
405 (nwrapper
406 (cond ((null owrapper)
407 (make-wrapper class))
408 ((and (equal nlayout olayout)
409 (not
410 (iterate ((o (list-elements owrapper-class-slots))
411 (n (list-elements nwrapper-class-slots)))
412 (unless (eq (car o) (car n)) (return t)))))
413 owrapper)
414 (t
415 ;;
416 ;; This will initialize the new wrapper to have the same
417 ;; state as the old wrapper. We will then have to change
418 ;; that. This may seem like wasted work (it is), but the
419 ;; spec requires that we call make-instances-obsolete.
420 ;;
421 (make-instances-obsolete class)
422 (class-wrapper class)))))
423 (with-slots (wrapper no-of-instance-slots slots) class
424 (setf no-of-instance-slots (length nlayout)
425 slots eslotds
426 (wrapper-instance-slots-layout nwrapper) nlayout
427 (wrapper-class-slots nwrapper) nwrapper-class-slots
428 wrapper nwrapper)))))
429
430 (defun compute-storage-info (cpl eslotds)
431 (let ((instance ())
432 (class ()))
433 (dolist (eslotd eslotds)
434 (let ((alloc (slotd-allocation eslotd)))
435 (cond ((eq alloc :instance) (push eslotd instance))
436 ((classp alloc) (push eslotd class)))))
437 (values (compute-layout cpl instance)
438 (compute-class-slots class))))
439
440 (defun compute-layout (cpl instance-eslotds)
441 (let* ((names
442 (gathering1 (collecting)
443 (dolist (eslotd instance-eslotds)
444 (when (eq (slotd-allocation eslotd) :instance)
445 (gather1 (slotd-name eslotd))))))
446 (order ()))
447 (labels ((rwalk (tail)
448 (when tail
449 (rwalk (cdr tail))
450 (dolist (ss (class-slots (car tail)))
451 (let ((n (slotd-name ss)))
452 (when (memq n names)
453 (setq order (cons n order)
454 names (remove n names))))))))
455 (rwalk cpl)
456 (reverse (append names order)))))
457
458 (defun compute-class-slots (eslotds)
459 (gathering1 (collecting)
460 (dolist (eslotd eslotds)
461 (gather1
462 (assoc (slotd-name eslotd)
463 (class-slot-cells (slotd-allocation eslotd)))))))
464
465 (defun update-inits (class inits)
466 (setf (plist-value class 'default-initargs) inits))
467
468
469 ;;;
470 ;;;
471 ;;;
472 (defmethod compute-default-initargs ((class std-class) cpl direct)
473 (labels ((walk (tail)
474 (if (null tail)
475 nil
476 (let ((c (pop tail)))
477 (append (if (eq c class)
478 direct
479 (class-direct-default-initargs c))
480 (walk tail))))))
481 (let ((initargs (walk cpl)))
482 (delete-duplicates initargs :test #'eq :key #'car :from-end t))))
483
484
485 ;;;
486 ;;; Protocols for constructing direct and effective slot definitions.
487 ;;;
488 ;;;
489 ;;;
490 ;;;
491 (defmethod direct-slot-definition-class ((class std-class) initargs)
492 (declare (ignore initargs))
493 (find-class 'standard-direct-slot-definition))
494
495 (defun make-direct-slotd (class initargs)
496 (let ((initargs (list* :class class initargs)))
497 (apply #'make-instance (direct-slot-definition-class class initargs) initargs)))
498
499 ;;;
500 ;;;
501 ;;;
502 (defmethod compute-slots ((class std-class) cpl class-direct-slots)
503 ;;
504 ;; As specified, we must call COMPUTE-EFFECTIVE-SLOT-DEFINITION once
505 ;; for each different slot name we find in our superclasses. Each
506 ;; call receives the class and a list of the dslotds with that name.
507 ;; The list is in most-specific-first order.
508 ;;
509 (let ((name-dslotds-alist ()))
510 (labels ((collect-one-class (dslotds)
511 (dolist (d dslotds)
512 (let* ((name (slotd-name d))
513 (entry (assq name name-dslotds-alist)))
514 (if entry
515 (push d (cdr entry))
516 (push (list name d) name-dslotds-alist))))))
517 (collect-one-class class-direct-slots)
518 (dolist (c (cdr cpl)) (collect-one-class (class-direct-slots c)))
519 (mapcar #'(lambda (direct)
520 (compute-effective-slot-definition class
521 (nreverse (cdr direct))))
522 name-dslotds-alist))))
523
524 (defmethod compute-effective-slot-definition ((class std-class) dslotds)
525 (let* ((initargs (compute-effective-slot-definition-initargs class dslotds))
526 (class (effective-slot-definition-class class initargs)))
527 (apply #'make-instance class initargs)))
528
529 (defmethod effective-slot-definition-class ((class std-class) initargs)
530 (declare (ignore initargs))
531 (find-class 'standard-effective-slot-definition))
532
533 (defmethod compute-effective-slot-definition-initargs
534 ((class std-class) direct-slotds)
535 (let* ((name nil)
536 (initfunction nil)
537 (initform nil)
538 (initargs nil)
539 (allocation nil)
540 (type t)
541 (namep nil)
542 (initp nil)
543 (allocp nil))
544
545 (dolist (slotd direct-slotds)
546 (when slotd
547 (unless namep
548 (setq name (slotd-name slotd)
549 namep t))
550 (unless initp
551 (when (slotd-initfunction slotd)
552 (setq initform (slotd-initform slotd)
553 initfunction (slotd-initfunction slotd)
554 initp t)))
555 (unless allocp
556 (setq allocation (slotd-allocation slotd)
557 allocp t))
558 (setq initargs (append (slotd-initargs slotd) initargs))
559 (let ((slotd-type (slotd-type slotd)))
560 (setq type (cond ((null type) slotd-type)
561 ((subtypep type slotd-type) type)
562 (t `(and ,type ,slotd-type)))))))
563 (list :name name
564 :initform initform
565 :initfunction initfunction
566 :initargs initargs
567 :allocation allocation
568 :type type)))
569
570
571 ;;;
572 ;;; NOTE: For bootstrapping considerations, these can't use make-instance
573 ;;; to make the method object. They have to use make-a-method which
574 ;;; is a specially bootstrapped mechanism for making standard methods.
575 ;;;
576 (defmethod add-reader-method ((class std-class) generic-function slot-name)
577 (let* ((name (class-name class))
578 (method (make-a-method 'standard-reader-method
579 ()
580 (list (or name 'standard-object))
581 (list class)
582 (make-reader-method-function class slot-name)
583 "automatically generated reader method"
584 slot-name)))
585 (add-method generic-function method)))
586
587 (defmethod add-writer-method ((class std-class) generic-function slot-name)
588 (let* ((name (class-name class))
589 (method (make-a-method 'standard-writer-method
590 ()
591 (list 'new-value (or name 'standard-object))
592 (list *the-class-t* class)
593 (make-writer-method-function class slot-name)
594 "automatically generated writer method"
595 slot-name)))
596 (add-method generic-function method)))
597
598
599 (defmethod remove-reader-method ((class std-class) generic-function)
600 (let ((method (get-method generic-function () (list class) nil)))
601 (when method (remove-method generic-function method))))
602
603 (defmethod remove-writer-method ((class std-class) generic-function)
604 (let ((method
605 (get-method generic-function () (list *the-class-t* class) nil)))
606 (when method (remove-method generic-function method))))
607
608
609 ;;;
610 ;;; make-reader-method-function and make-write-method function are NOT part of
611 ;;; the standard protocol. They are however useful, PCL makes uses makes use
612 ;;; of them internally and documents them for PCL users.
613 ;;;
614 ;;; *** This needs work to make type testing by the writer functions which
615 ;;; *** do type testing faster. The idea would be to have one constructor
616 ;;; *** for each possible type test. In order to do this it would be nice
617 ;;; *** to have help from inform-type-system-about-class and friends.
618 ;;;
619 ;;; *** There is a subtle bug here which is going to have to be fixed.
620 ;;; *** Namely, the simplistic use of the template has to be fixed. We
621 ;;; *** have to give the optimize-slot-value method the user might have
622 ;;; *** defined for this metclass a chance to run.
623 ;;;
624 (defmethod make-reader-method-function ((class standard-class) slot-name)
625 (make-std-reader-method-function slot-name))
626
627 (defmethod make-writer-method-function ((class standard-class) slot-name)
628 (make-std-writer-method-function slot-name))
629
630 (defun make-std-reader-method-function (slot-name)
631 #'(lambda (instance)
632 (slot-value-using-class (wrapper-class (get-wrapper instance))
633 instance
634 slot-name)))
635
636 (defun make-std-writer-method-function (slot-name)
637 #'(lambda (nv instance)
638 (setf (slot-value-using-class (wrapper-class (get-wrapper instance))
639 instance
640 slot-name)
641 nv)))
642
643
644
645 ;;;; inform-type-system-about-class
646 ;;;; make-type-predicate
647 ;;;
648 ;;; These are NOT part of the standard protocol. They are internal mechanism
649 ;;; which PCL uses to *try* and tell the type system about class definitions.
650 ;;; In a more fully integrated implementation of CLOS, the type system would
651 ;;; know about class objects and class names in a more fundamental way and
652 ;;; the mechanism used to inform the type system about new classes would be
653 ;;; different.
654 ;;;
655 (defmethod inform-type-system-about-class ((class std-class) name)
656 (let ((predicate-name (make-type-predicate-name name)))
657 (setf (symbol-function predicate-name) (make-type-predicate name))
658 (do-satisfies-deftype name predicate-name)))
659
660 (defun make-type-predicate (name)
661 #'(lambda (x)
662 (not
663 (null
664 (memq (find-class name)
665 (cond ((std-instance-p x)
666 (class-precedence-list (std-instance-class x)))
667 ((fsc-instance-p x)
668 (class-precedence-list (fsc-instance-class x)))))))))
669
670
671 ;;;
672 ;;; These 4 definitions appear here for bootstrapping reasons. Logically,
673 ;;; they should be in the construct file. For documentation purposes, a
674 ;;; copy of these definitions appears in the construct file. If you change
675 ;;; one of the definitions here, be sure to change the copy there.
676 ;;;
677 (defvar *initialization-generic-functions*
678 (list #'make-instance
679 #'default-initargs
680 #'allocate-instance
681 #'initialize-instance
682 #'shared-initialize))
683
684 (defmethod maybe-update-constructors
685 ((generic-function generic-function)
686 (method method))
687 (when (memq generic-function *initialization-generic-functions*)
688 (labels ((recurse (class)
689 (update-constructors class)
690 (dolist (subclass (class-direct-subclasses class))
691 (recurse subclass))))
692 (when (classp (car (method-specializers method)))
693 (recurse (car (method-specializers method)))))))
694
695 (defmethod update-constructors ((class std-class))
696 (dolist (cons (class-constructors class))
697 (install-lazy-constructor-installer cons)))
698
699 (defmethod update-constructors ((class class))
700 ())
701
702
703
704 (defmethod compatible-meta-class-change-p (class proto-new-class)
705 (eq (class-of class) (class-of proto-new-class)))
706
707 (defmethod check-super-metaclass-compatibility ((class t) (new-super t))
708 (unless (eq (class-of class) (class-of new-super))
709 (error "The class ~S was specified as a~%super-class of the class ~S;~%~
710 but the meta-classes ~S and~%~S are incompatible."
711 new-super class (class-of new-super) (class-of class))))
712
713
714 ;;;
715 ;;;
716 ;;;
717 (defun force-cache-flushes (class)
718 (let* ((owrapper (class-wrapper class))
719 (state (wrapper-state owrapper)))
720 ;;
721 ;; We only need to do something if the state is still T. If the
722 ;; state isn't T, it will be FLUSH or OBSOLETE, and both of those
723 ;; will already be doing what we want. In particular, we must be
724 ;; sure we never change an OBSOLETE into a FLUSH since OBSOLETE
725 ;; means do what FLUSH does and then some.
726 ;;
727 (when (eq state 't)
728 (let ((nwrapper (make-wrapper class)))
729 (setf (wrapper-instance-slots-layout nwrapper)
730 (wrapper-instance-slots-layout owrapper))
731 (setf (wrapper-class-slots nwrapper)
732 (wrapper-class-slots owrapper))
733 (without-interrupts
734 (setf (slot-value class 'wrapper) nwrapper)
735 (invalidate-wrapper owrapper 'flush nwrapper))
736 (update-constructors class))))) ;??? ***
737
738 (defun flush-cache-trap (owrapper nwrapper instance)
739 (declare (ignore owrapper))
740 (set-wrapper instance nwrapper))
741
742
743
744 ;;;
745 ;;; make-instances-obsolete can be called by user code. It will cause the
746 ;;; next access to the instance (as defined in 88-002R) to trap through the
747 ;;; update-instance-for-redefined-class mechanism.
748 ;;;
749 (defmethod make-instances-obsolete ((class std-class))
750 (let ((owrapper (class-wrapper class))
751 (nwrapper (make-wrapper class)))
752 (setf (wrapper-instance-slots-layout nwrapper)
753 (wrapper-instance-slots-layout owrapper))
754 (setf (wrapper-class-slots nwrapper)
755 (wrapper-class-slots owrapper))
756 (without-interrupts
757 (setf (slot-value class 'wrapper) nwrapper)
758 (invalidate-wrapper owrapper 'obsolete nwrapper)
759 class)))
760
761 (defmethod make-instances-obsolete ((class symbol))
762 (make-instances-obsolete (find-class class)))
763
764
765 ;;;
766 ;;; obsolete-instance-trap is the internal trap that is called when we see
767 ;;; an obsolete instance. The times when it is called are:
768 ;;; - when the instance is involved in method lookup
769 ;;; - when attempting to access a slot of an instance
770 ;;;
771 ;;; It is not called by class-of, wrapper-of, or any of the low-level instance
772 ;;; access macros.
773 ;;;
774 ;;; Of course these times when it is called are an internal implementation
775 ;;; detail of PCL and are not part of the documented description of when the
776 ;;; obsolete instance update happens. The documented description is as it
777 ;;; appears in 88-002R.
778 ;;;
779 ;;; This has to return the new wrapper, so it counts on all the methods on
780 ;;; obsolete-instance-trap-internal to return the new wrapper. It also does
781 ;;; a little internal error checking to make sure that the traps are only
782 ;;; happening when they should, and that the trap methods are computing
783 ;;; apropriate new wrappers.
784 ;;;
785 (defun obsolete-instance-trap (owrapper nwrapper instance)
786 ;;
787 ;; local --> local transfer
788 ;; local --> shared discard
789 ;; local --> -- discard
790 ;; shared --> local transfer
791 ;; shared --> shared discard
792 ;; shared --> -- discard
793 ;; -- --> local add
794 ;; -- --> shared --
795 ;;
796 (let* ((class (wrapper-class nwrapper))
797 (guts (allocate-instance class)) ;??? allocate-instance ???
798 (olayout (wrapper-instance-slots-layout owrapper))
799 (nlayout (wrapper-instance-slots-layout nwrapper))
800 (oslots (get-slots instance))
801 (nslots (get-slots guts))
802 (oclass-slots (wrapper-class-slots owrapper))
803 (added ())
804 (discarded ())
805 (plist ()))
806 ;;
807 ;; Go through all the old local slots.
808 ;;
809 (iterate ((name (list-elements olayout))
810 (opos (interval :from 0)))
811 (let ((npos (posq name nlayout)))
812 (if npos
813 (setf (svref nslots npos) (svref oslots opos))
814 (progn (push name discarded)
815 (unless (eq (svref oslots opos) *slot-unbound*)
816 (setf (getf plist name) (svref oslots opos)))))))
817 ;;
818 ;; Go through all the old shared slots.
819 ;;
820 (iterate ((oclass-slot-and-val (list-elements oclass-slots)))
821 (let ((name (car oclass-slot-and-val))
822 (val (cdr oclass-slot-and-val)))
823 (let ((npos (posq name nlayout)))
824 (if npos
825 (setf (svref nslots npos) (cdr oclass-slot-and-val))
826 (progn (push name discarded)
827 (unless (eq val *slot-unbound*)
828 (setf (getf plist name) val)))))))
829 ;;
830 ;; Go through all the new local slots to compute the added slots.
831 ;;
832 (dolist (nlocal nlayout)
833 (unless (or (memq nlocal olayout)
834 (assq nlocal oclass-slots))
835 (push nlocal added)))
836
837 (without-interrupts
838 (set-wrapper instance nwrapper)
839 (set-slots instance nslots))
840
841 (update-instance-for-redefined-class instance
842 added
843 discarded
844 plist)
845 nwrapper))
846
847
848
849 ;;;
850 ;;;
851 ;;;
852 (defmacro change-class-internal (wrapper-fetcher slots-fetcher alloc)
853 `(let* ((old-class (class-of instance))
854 (copy (,alloc old-class))
855 (guts (,alloc new-class))
856 (new-wrapper (,wrapper-fetcher guts))
857 (old-wrapper (class-wrapper old-class))
858 (old-layout (wrapper-instance-slots-layout old-wrapper))
859 (new-layout (wrapper-instance-slots-layout new-wrapper))
860 (old-slots (,slots-fetcher instance))
861 (new-slots (,slots-fetcher guts))
862 (old-class-slots (wrapper-class-slots old-wrapper)))
863
864 ;;
865 ;; "The values of local slots specified by both the class Cto and
866 ;; Cfrom are retained. If such a local slot was unbound, it remains
867 ;; unbound."
868 ;;
869 (iterate ((new-slot (list-elements new-layout))
870 (new-position (interval :from 0)))
871 (let ((old-position (position new-slot old-layout :test #'eq)))
872 (when old-position
873 (setf (svref new-slots new-position)
874 (svref old-slots old-position)))))
875
876 ;;
877 ;; "The values of slots specified as shared in the class Cfrom and
878 ;; as local in the class Cto are retained."
879 ;;
880 (iterate ((slot-and-val (list-elements old-class-slots)))
881 (let ((position (position (car slot-and-val) new-layout :test #'eq)))
882 (when position
883 (setf (svref new-slots position) (cdr slot-and-val)))))
884
885 ;; Make the copy point to the old instance's storage, and make the
886 ;; old instance point to the new storage.
887 (without-interrupts
888 (setf (,slots-fetcher copy) old-slots)
889
890 (setf (,wrapper-fetcher instance) new-wrapper)
891 (setf (,slots-fetcher instance) new-slots))
892
893 (update-instance-for-different-class copy instance)
894 instance))
895
896 (defmethod change-class ((instance standard-object)
897 (new-class standard-class))
898 (unless (std-instance-p instance)
899 (error "Can't change the class of ~S to ~S~@
900 because it isn't already an instance with metaclass~%~S."
901 instance
902 new-class
903 'standard-class))
904 (change-class-internal std-instance-wrapper
905 std-instance-slots
906 allocate-instance))
907
908 (defmethod change-class ((instance standard-object)
909 (new-class funcallable-standard-class))
910 (unless (fsc-instance-p instance)
911 (error "Can't change the class of ~S to ~S~@
912 because it isn't already an instance with metaclass~%~S."
913 instance
914 new-class
915 'funcallable-standard-class))
916 (change-class-internal fsc-instance-wrapper
917 fsc-instance-slots
918 allocate-instance))
919
920 (defmethod change-class ((instance t) (new-class-name symbol))
921 (change-class instance (find-class new-class-name)))
922
923
924
925 ;;;
926 ;;; The metaclass BUILT-IN-CLASS
927 ;;;
928 ;;; This metaclass is something of a weird creature. By this point, all
929 ;;; instances of it which will exist have been created, and no instance
930 ;;; is ever created by calling MAKE-INSTANCE.
931 ;;;
932 ;;; But, there are other parts of the protcol we must follow and those
933 ;;; definitions appear here.
934 ;;;
935 (defmethod shared-initialize :before
936 ((class built-in-class) slot-names &rest initargs)
937 (declare (ignore slot-names))
938 (error "Attempt to initialize or reinitialize a built in class."))
939
940 (defmethod class-direct-slots ((class built-in-class)) ())
941 (defmethod class-slots ((class built-in-class)) ())
942 (defmethod class-direct-default-initargs ((class built-in-class)) ())
943 (defmethod class-default-initargs ((class built-in-class)) ())
944
945 (defmethod check-super-metaclass-compatibility ((c class) (s built-in-class))
946 (or (eq s *the-class-t*)
947 (error "~S cannot have ~S as a super.~%~
948 The class ~S is the only built in class that can be a~%~
949 superclass of a standard class."
950 c s *the-class-t*)))
951
952
953 ;;;
954 ;;;
955 ;;;
956
957 (defmethod check-super-metaclass-compatibility ((c std-class)
958 (f forward-referenced-class))
959 't)
960
961
962 ;;;
963 ;;;
964 ;;;
965
966 (defmethod add-dependent ((metaobject dependent-update-mixin) dependent)
967 (pushnew dependent (plist-value metaobject 'dependents)))
968
969 (defmethod remove-dependent ((metaobject dependent-update-mixin) dependent)
970 (setf (plist-value metaobject 'dependents)
971 (delete dependent (plist-value metaobject 'dependents))))
972
973 (defmethod map-dependents ((metaobject dependent-update-mixin) function)
974 (dolist (dependent (plist-value metaobject 'dependents))

  ViewVC Help
Powered by ViewVC 1.1.5