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

  ViewVC Help
Powered by ViewVC 1.1.5