/[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 - (hide 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 wlott 1.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