[comp.sources.unix] v11i044: Patch for Common objects sources

rs@uunet.UU.NET (Rich Salz) (09/16/87)

Submitted-by:          hplabs!hplabsz!kempf@rutgers.edu
Posting-number: Volume 11, Issue 44
Archive-name: comobj.pch

[  New versions of two files that were mostly mangled last time.  --r$  ]
-----CUT-----HERE---
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# This archive contains:
#	fixup.l	
#	methods.l	
# Error checking via wc(1) will be performed.

LANG=""; export LANG

echo x - fixup.l
cat >fixup.l <<'@EOF'
;;;-*-Mode:LISP; Package: PCL; Base:10; Syntax:Common-lisp; Patch-File: Yes -*-
;;;
;;; *************************************************************************
;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
;;;
;;; Use and copying of this software and preparation of derivative works
;;; based upon this software are permitted.  Any distribution of this
;;; software or derivative works must comply with all applicable United
;;; States export control laws.
;;; 
;;; This software is made available AS IS, and Xerox Corporation makes no
;;; warranty about the software, its performance or its conformity to any
;;; specification.
;;; 
;;; Any person obtaining a copy of this software is requested to send their
;;; name and post office or electronic mail address to:
;;;   CommonLoops Coordinator
;;;   Xerox Artifical Intelligence Systems
;;;   2400 Hanover St.
;;;   Palo Alto, CA 94303
;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
;;;
;;; Suggestions, comments and requests for improvements are also welcome.
;;; *************************************************************************
;;;

(in-package 'pcl)

(eval-when (compile load eval)
  (setq *real-methods-exist-p* nil)
  (setf (symbol-function 'expand-defmeth)
	(symbol-function 'real-expand-defmeth)))

(eval-when (load)
  (clrhash *discriminator-name-hash-table*)
  (fix-early-defmeths)
 ;; This now happens at the end of loading HIGH to make it
 ;; possible to compile and load pcl in the same environment.
 ;(setq *error-when-defining-method-on-existing-function* t)
  )

(eval-when (compile load eval)
  (setq *real-methods-exist-p* t))

  ;;   
;;;;;; Pending defmeths which I couldn't do before.
  ;;


(eval-when (load eval)
  (setf (discriminator-named 'print-instance) ())
  (make-specializable 'print-instance :arglist '(instance stream depth)))

(defmeth print-instance ((instance object) stream depth)
  (let ((length (if (numberp *print-length*) (* *print-length* 2) nil)))
    (format stream "#S(~S" (class-name (class-of instance)))
    (iterate ((slot-or-value in (all-slots instance))
	      (slotp = t (not slotp)))
      (when (numberp length)
	(cond ((<= length 0) (format stream " ...") (return ()))
	      (t (decf length))))
      (princ " " stream)
      (let ((*print-level* (cond ((null *print-level*) ())
				 (slotp 1)
				 (t (- *print-level* depth)))))
	(if (and *print-level* (<= *print-level* 0))
	    (princ "#" stream)
	    (prin1 slot-or-value stream))))
    (princ ")" stream)))

(defmeth print-instance ((class essential-class) stream depth)
  (named-object-print-function class stream depth))


(defmethod print-instance ((method essential-method) stream depth)
  (ignore depth)
  (printing-random-thing (method stream)
    (let ((discriminator (method-discriminator method))
	  (class-name (capitalize-words (class-name (class-of method)))))
      (format stream "~A ~S ~:S"
	      class-name
	      (and discriminator (discriminator-name discriminator))
	      (method-type-specifiers method)))))

(defmethod print-instance ((method basic-method) stream depth)
  (ignore depth)
  (printing-random-thing (method stream)
    (let ((discriminator (method-discriminator method))
	  (class-name (capitalize-words (class-name (class-of method)))))
      (format stream "~A ~S ~:S"
	      class-name
	      (and discriminator (discriminator-name discriminator))
	      (unparse-type-specifiers method)))))

(defmethod print-instance ((discriminator essential-discriminator) stream depth)
  (named-object-print-function discriminator stream depth))

(defmethod print-instance ((discriminator basic-discriminator) stream depth)
  (named-object-print-function
    discriminator stream depth (list (method-combination-type discriminator))))

(eval-when (load)

(define-meta-class essential-class (lambda (x) (%instance-ref x 0)))

(defmeth class-slots ((class essential-class))
  (ignore class)
  ())

(defmeth make-instance ((class essential-class))
  (let ((primitive-instance
	  (%make-instance (class-named 'essential-class)
			  (1+ (length (class-slots class))))))
    (setf (%instance-ref primitive-instance 0) class)
    primitive-instance))

(defmeth get-slot-using-class ((class essential-class) object slot-name)
  (let ((pos (position slot-name (class-slots class) :key #'slotd-name)))
    (if pos
	(%instance-ref object (1+ pos))
	(slot-missing ;class
	  object slot-name))))

(defmeth put-slot-using-class ((class essential-class)
			       object
			       slot-name
			       new-value)
  (let ((pos (position slot-name (class-slots class) :key #'slotd-name)))
    (if pos
	(setf (%instance-ref object (1+ pos)) new-value)
	(slot-missing ;class
		      object slot-name))))

(defmeth optimize-get-slot (class form)
  (declare (ignore class))
  form)

(defmeth optimize-setf-of-get-slot (class form)
  (declare (ignore class))
  form)

(defmeth make-slotd ((class essential-class) &rest keywords-and-options)
  (ignore class)
  (apply #'make-slotd--essential-class keywords-and-options))

(defmeth add-named-class ((proto-class essential-class) name
			  local-supers
			  local-slot-slotds
			  extra)
  ;; First find out if there is already a class with this name.
  ;; If there is, call class-for-redefinition to get the class
  ;; object to use for the new definition.  If there is no exisiting
  ;; class we just make a new instance.
  (let* ((existing (class-named name t))
	 (class (if existing
		    (class-for-redefinition existing proto-class name 
					    local-supers local-slot-slotds
					    extra)
		    (make (class-of proto-class)))))

    (setq local-supers
	  (mapcar
	    #'(lambda (ls)
		(or (class-named ls t)
		    (error "~S was specified as the name of a local-super~%~
                            for the class named ~S.  But there is no class~%~
                            class named ~S." ls name ls)))
	    local-supers))
    
    (setf (class-name class) name)
;   (setf (class-ds-options class) extra)	;This is NOT part of the
;						;standard protocol.
   
    (add-class class local-supers local-slot-slotds extra)
    
    (setf (class-named name) class)
    name))

(defmeth supers-changed ((class essential-class)
			 old-local-supers
			 old-local-slots
			 extra
			 top-p)
  (ignore old-local-supers old-local-slots top-p)
  (let ((cpl (compute-class-precedence-list class)))
    (setf (class-class-precedence-list class) cpl)
;   (update-slots--class class cpl)		         ;This is NOT part of
;						         ;the essential-class
;						         ;protocol.
    (dolist (sub-class (class-direct-subclasses class))
      (supers-changed sub-class
		      (class-local-supers sub-class)
		      (class-local-slots sub-class)
		      extra
		      nil))
;   (when top-p                                          ;This is NOT part of
;     (update-method-inheritance class old-local-supers));the essential-class
; 					                 ;protocol.
    ))

(defmeth slots-changed ((class essential-class)
			old-local-slots
			extra
			top-p)
  (ignore top-p old-local-slots)
  ;; When this is called, class should have its local-supers and
  ;; local-slots slots filled in properly.
; (update-slots--class class (class-class-precedence-list class))
  (dolist (sub-class (class-direct-subclasses class))
    (slots-changed sub-class (class-local-slots sub-class) extra nil)))

(defmeth method-equal (method argument-specifiers options)
  (ignore options)
  (equal argument-specifiers (method-type-specifiers method)))

(defmeth methods-combine-p ((d essential-discriminator))
  (ignore d)
  nil)

)

  ;;   
;;;;;; 
  ;;

(define-method-body-macro call-next-method ()
  :global :error
  :method (expand-call-next-method
	    (macroexpand-time-method macroexpand-time-environment)
	    nil
	    macroexpand-time-environment))

(defmethod expand-call-next-method ((mex-method method) args mti)
  (ignore args)
  (let* ((arglist (and mex-method (method-arglist mex-method)))
	 (uid (macroexpand-time-method-uid mti))
	 (load-method-1-args (macroexpand-time-load-method-1-args mti))
	 (load-time-eval-form `(load-time-eval
				 (if (boundp ',uid)
				     ,uid
				     (setq ,uid
					   (apply #'load-method-1
						  ',load-method-1-args)))))
	 (applyp nil))
    (multiple-value-setq (arglist applyp) (make-call-arguments arglist))
    (cond ((null (method-type-specifiers mex-method))
	   (warn "Using call-next-method in a default method.~%~
                  At run time this will generate an error.")
	   '(error "Using call-next-method in a default method."))
	  (applyp
	   `(apply
	      #'call-next-method-internal ,load-time-eval-form . ,arglist))
	  (t
	   `(call-next-method-internal ,load-time-eval-form . ,arglist)))))

(defun call-next-method-internal (current-method &rest args)
  (let* ((discriminator (method-discriminator current-method))
	 (type-specifiers (method-type-specifiers current-method))
	 (most-specific nil)
	 (most-specific-type-specifiers ())
	 (dispatch-order (get-slot--class discriminator 'dispatch-order)))
    (iterate ((method in (discriminator-methods discriminator)))
      (let ((method-type-specifiers (method-type-specifiers method))
            (temp ()))
        (and (every #'(lambda (arg type-spec)
			(or (eq type-spec 't)
			    (memq type-spec
				  (get-slot--class
				    (class-of arg) 'class-precedence-list))))
                    args method-type-specifiers)
             (eql 1 (setq temp (compare-type-specifier-lists
				 type-specifiers
				 method-type-specifiers
				 ()
				 args
				 ()
				 dispatch-order)))
             (or (null most-specific)
                 (eql 1 (setq temp (compare-type-specifier-lists
                                     method-type-specifiers
                                     most-specific-type-specifiers
                                     ()
                                     args
                                     ()
				     dispatch-order))))
             (setq most-specific method
                   most-specific-type-specifiers method-type-specifiers))))
    (if (or most-specific
            (setq most-specific (discriminator-default-method
				  discriminator)))
        (apply (method-function most-specific) args)
        (error "no super method found"))))

;;;
;;; This is kind of bozoid because it always copies the lambda-list even
;;; when it doesn't need to.  It also doesn't remember things it could
;;; remember, causing it to call memq more than it should.  Fix this one
;;; day when there is nothing else to do.
;;; 
(defun make-call-arguments (lambda-list &aux applyp)
  (setq lambda-list (reverse lambda-list))
  (when (memq '&aux lambda-list)
    (setq lambda-list (cdr (memq '&aux lambda-list))))
  (setq lambda-list (nreverse lambda-list))
  (let ((optional (memq '&optional lambda-list)))
    (when optional
      ;; The &optional keyword appears in the lambda list.
      ;; Get rid of it, by moving the rest of the lambda list
      ;; up, then go through the optional arguments, replacing
      ;; them with the real symbol.
      (setf (car optional) (cadr optional)
	    (cdr optional) (cddr optional))
      (iterate ((loc on optional))
	(when (memq (car loc) lambda-list-keywords)
	  (unless (memq (car loc) '(&rest &key &allow-other-keys))
	    (error
	      "The non-standard lambda list keyword ~S appeared in the~%~
               lambda list of a method in which CALL-NEXT-METHOD is used.~%~
               PCL can only deal with standard lambda list keywords."))
	  (when (listp (car loc)) (setf (car loc) (caar loc)))))))
  (let ((rest (memq '&rest lambda-list)))
    (cond ((not (null rest))
	   ;; &rest appears in the lambda list. This means we
	   ;; have to do an apply. We ignore the rest of the
	   ;; lambda list, just grab the &rest var and set applyp.
	   (setf (car rest) (if (listp (cadr rest))
				(caadr rest)
				(cadr rest))
		 (cdr rest) ())
	   (setq applyp t))
	  (t
	   (let ((key (memq '&key lambda-list)))
	     (when key
	       ;; &key appears in the lambda list.  Remove &key from the
	       ;; lambda list then replace all the keywords with pairs of
	       ;; the actual keyword followed by the value variable.
	       ;; Have to parse the hairy triple case of &key.
	       (let ((key-args
		       (iterate ((arg in (cdr key)))
			 (until (eq arg '&allow-other-keys))
			 (cond ((symbolp arg)
				(collect (make-keyword arg))
				(collect arg))
			       ((cddr arg)
				(collect (caddr arg))
				(collect (car arg)))
			       (t
				(collect (make-keyword (car arg)))
				(collect (car arg)))))))
		 (if key-args
		     (setf (car key) (car key-args)
			   (cdr key) (cdr key-args))
		     (setf (cdr key) nil
			   lambda-list (remove '&key lambda-list)))))))))
  (values lambda-list applyp))
@EOF
if test "`wc -lwc <fixup.l`" != '    355   1302  12760'
then
 echo ERROR: wc results of fixup.l are `wc -lwc <fixup.l` should be 355   1302  12760
fi
chmod 666 fixup.l

LANG=""; export LANG

echo x - methods.l
cat >methods.l <<'@EOF'
;;;-*-Mode:LISP; Package: PCL; Base:10; Syntax:Common-lisp -*-
;;;
;;; *************************************************************************
;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
;;;
;;; Use and copying of this software and preparation of derivative works
;;; based upon this software are permitted.  Any distribution of this
;;; software or derivative works must comply with all applicable United
;;; States export control laws.
;;; 
;;; This software is made available AS IS, and Xerox Corporation makes no
;;; warranty about the software, its performance or its conformity to any
;;; specification.
;;; 
;;; Any person obtaining a copy of this software is requested to send their
;;; name and post office or electronic mail address to:
;;;   CommonLoops Coordinator
;;;   Xerox Artifical Intelligence Systems
;;;   2400 Hanover St.
;;;   Palo Alto, CA 94303
;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
;;;
;;; Suggestions, comments and requests for improvements are also welcome.
;;; *************************************************************************
;;;

(in-package 'pcl)

  ;;   
;;;;;; Methods
  ;;   

(ndefstruct (essential-method
	      (:class class)
	      (:conc-name method-))
  (discriminator nil)
  (arglist ())
  (type-specifiers ())
  (function nil))

(ndefstruct (combinable-method-mixin (:class class)))

(ndefstruct (basic-method
	      (:class class)
	      (:include (essential-method))
	      (:constructor make-method-1)
	      (:conc-name method-))
  (function nil)
  (discriminator nil)
  (type-specifiers ())
  (arglist ())
  (options () :allocation :dynamic))

(ndefstruct (method (:class class)
		    (:include (combinable-method-mixin
			       basic-method))))


(ndefstruct (essential-discriminator
	      (:class class)
	      (:conc-name discriminator-))
  (name nil)
  (methods ())
  (discriminating-function ())
  (classical-method-table nil :allocation :dynamic)
  (cache ()))

(ndefstruct (method-combination-mixin (:class class)
				      (:conc-name nil))
  (method-combination-type :daemon)
  (method-combination-parameters ())
  (methods-combine-p ())
  )

(ndefstruct (basic-discriminator
	      (:class class)
	      (:include (essential-discriminator))
	      (:constructor make-discriminator-1)
	      (:conc-name discriminator-))

  (dispatch-order :default)  
  (inactive-methods () :allocation :dynamic))

(ndefstruct (discriminator (:class class)
			   (:include (method-combination-mixin
				      basic-discriminator)))
  )

;;;
;;; This is really just for bootstrapping, of course this isn't all
;;; worked out yet.  But this SHOULD really just be for bootstrapping.
;;; 
(defmeth method-causes-combination-p ((method basic-method))
  (ignore method)
  ())

  ;;   
;;;;;; 
  ;;   


(defun real-expand-defmeth (name&options arglist body)
  (unless (listp name&options) (setq name&options (list name&options)))
  (keyword-parse ((discriminator-class 'discriminator)
                  (method-class 'method))
                 (cdr name&options)
    (dolist (x '(:discriminator-class :method-class))
      (delete x name&options :test #'(lambda (x y)
				       (and (listp y) (eq (car y) x)))))
    (let ((discriminator-class-object (class-named discriminator-class t))
          (method-class-object (class-named method-class t)))
      (or discriminator-class-object		;
          (error
	    "The :DISCRIMINATOR-CLASS option to defmeth was used to specify~
             that the class~%of the discriminator should be ~S;~%~
             but there is no class named ~S."
	    discriminator-class
	    discriminator-class))
      (or method-class-object
          (error "The :METHOD-CLASS option to defmeth was used to specify~%~
                  that the class of the method should be ~S;~%~
                  but there is no class named ~S."
                 method-class
                 method-class))
      (expand-defmeth-internal (class-prototype discriminator-class-object)
			       (class-prototype method-class-object)
			       name&options
			       arglist
			       body))))

(defvar *method-being-defined*)

(defmeth expand-defmeth-internal ((proto-discriminator basic-discriminator)
				  (proto-method basic-method)
				  name&options arglist body)
  (keyword-parse ((setf () setf-specified-p))
                 (cdr name&options)
    (let* ((discriminator-class-name (class-name
				       (class-of proto-discriminator)))
           (method-class-name (class-name (class-of proto-method)))
           (name (car name&options))
           (merged-arglist (cons (car arglist) (append setf (cdr arglist))))
           (merged-args (arglist-without-type-specifiers proto-discriminator
                                                         proto-method
                                                         merged-arglist))
           (merged-type-specifiers
	     (defmethod-argument-specializers arglist))
           discriminator-name
           method-name
	   (defmethod-uid (gensym))
	   (load-method-1 ())
	   (documentation ())
	   (declarations ()))
      (if setf-specified-p
	  (setq discriminator-name (make-setf-discriminator-name name)
		method-name (make-setf-method-name name
						   (arglist-type-specifiers
						     proto-discriminator
						     proto-method
						     setf)
						   merged-type-specifiers))
	  (setq discriminator-name name
		method-name (make-method-name name
					      merged-type-specifiers)))
      (multiple-value-setq (documentation declarations body)
	(extract-declarations body))
      (setq load-method-1 `(,discriminator-class-name
			    ,method-class-name
			    ,discriminator-name
			    ,merged-type-specifiers
			    ,merged-args
			    ,(cdr name&options)))
      ;;
      ;; There are 4 cases:
      ;;   - evaluated
      ;;   - compiled to core
      ;;   - compiled to file
      ;;   - loading the compiled file
      ;;
      ;; When loading a method which has a run-super in it, there is no way
      ;; to know which of two events will happen first:
      ;;   1. the load-time-eval form in the run super will be
      ;;      evaluated first, or
      ;;   2. the function to install the loaded method (defmethod-uid)
      ;;      will be evaluated first.
      ;; consequently, both the special function (defmethod-uid) and the
      ;; expansion of run-super must check to see if the other has already
      ;; run and set the value of defmethod-uid to the method involved.
      ;; This is what causes the boundp checks of defmethod-uid each time
      ;; before it is set.
      ;; 
      `(progn
	 
	 (eval-when (eval load)
	   
	   (defun ,defmethod-uid ()
	     (declare (special ,defmethod-uid))
	     (unless (boundp ',defmethod-uid)
	       (setq ,defmethod-uid (apply #'load-method-1
					   ',load-method-1)))
	     ,@(and *real-methods-exist-p*
		    `((record-definition
			',discriminator-name 'method
			',merged-type-specifiers ',(cdr name&options))
		      (setf (symbol-function ',method-name)
			    #'(lambda ,merged-args
				,@documentation
				,@declarations
				(declare (method-function-name ,method-name))
				,(wrap-method-body
				   proto-discriminator
				   (apply 'compile-method-1 load-method-1)
				   discriminator-name
				   defmethod-uid
				   load-method-1
				   body)
				))))
	     
	     (setf (method-function ,defmethod-uid)
		   (symbol-function ',method-name))
	     
	     (add-method (discriminator-named ',discriminator-name)
			 ,defmethod-uid
			 ()))
	   
	   (,defmethod-uid))
	 
	 (eval-when (compile load eval)
	   
	   ,@(and setf-specified-p
		  `((record-definition
		      ',name 'defsetf ',discriminator-name 'defmeth)
		    (defsetf ,name
			     ,(arglist-without-type-specifiers
				proto-discriminator proto-method arglist)
			     ,(arglist-without-type-specifiers
				proto-discriminator proto-method setf)
		      (list ',discriminator-name ,@(arglist-args
						     proto-discriminator
						     proto-method
						     merged-args)))))
	   
	   ',discriminator-name)))))

(defmethod wrap-method-body ((mex-generic-function discriminator)
			     (mex-method method)
			     generic-function-name
			     method-uid
			     load-method-1-args
			     body)
  (let ((macroexpand-time-information (list mex-generic-function
					    mex-method
					    generic-function-name
					    method-uid
					    load-method-1-args)))
    `(macrolet ,(iterate (((name arglist params fn) in *method-body-macros*))
		  (collect `(,name ,arglist
			       (funcall (function ,fn)
					',macroexpand-time-information
					,@params))))
       (block ,generic-function-name
	 . ,body))))

(defun macroexpand-time-generic-function (mti) (nth 0 mti))

(defun macroexpand-time-method (mti) (nth 1 mti))

(defun macroexpand-time-generic-function-name (mti) (nth 2 mti))

(defun macroexpand-time-method-uid (mti) (nth 3 mti))

(defun macroexpand-time-load-method-1-args (mti) (nth 4 mti))


(defun load-method-1 (discriminator-class-name
		       method-class-name
		       discriminator-name
		       method-type-specifiers
		      method-arglist
		      options)
  (let* ((discriminator
	   (ensure-selector-specializable
	     (class-prototype (class-named discriminator-class-name))
	     discriminator-name
	     method-arglist))
	 (method
	   (or (find-method discriminator method-type-specifiers options t)
	       (make method-class-name))))
    (setf (method-arglist method) method-arglist)
    (setf (method-type-specifiers method)
	  (parse-type-specifiers
	    discriminator method method-type-specifiers))
    (setf (method-options method) options)
    method))

(defun compile-method-1 (discriminator-class-name
			 method-class-name
			 discriminator-name
			 method-type-specifiers
			 method-arglist
			 options)
  (ignore discriminator-name)
  (let ((method (make method-class-name)))
    (setf (method-arglist method) method-arglist)
    (setf (method-type-specifiers method)
          (parse-type-specifiers
	    (class-prototype (class-named discriminator-class-name))
	    method
	    method-type-specifiers))
    (setf (method-options method) options)
    method))



(defmeth add-named-method ((proto-discriminator essential-discriminator)
			   (proto-method essential-method)
			   discriminator-name
			   arglist
			   type-specs
			   extra
			   function)
  ;; What about changing the class of the discriminator if there is
  ;; one.  Whose job is that anyways.  Do we need something kind of
  ;; like class-for-redefinition?
  (let* ((discriminator
	   ;; Modulo bootstrapping hair, this is just:
	   ;;   (or (discriminator-named ..)
	   ;;       (make-specializable))
	   (ensure-selector-specializable proto-discriminator
					  discriminator-name
					  arglist))
	 (existing (find-method discriminator type-specs extra t))
	 (method (or existing
		     (make (class-of proto-method)))))
    (when existing (change-class method (class-of proto-method)))
    (setf (method-arglist method) arglist)
    (setf (method-function method) function)
    (setf (method-type-specifiers method) type-specs)
    (add-method discriminator method extra)))

(defmeth add-method ((discriminator essential-discriminator)
		     (method essential-method)
		     extra)
  (ignore extra)
  (let ((type-specs (method-type-specifiers method))
       ;(options (method-options method))
       ;(methods (discriminator-methods discriminator))
	)
    (setf (method-discriminator method) discriminator)
;    ;; Put the new method where it belongs, either:
;    ;;  - The same (EQ) method object is already on discriminator-methods
;    ;;    of the discriminator so we don't need to do anything to put the
;    ;;    new methods where it belongs.
;    ;;  - There is an method on discriminator-methods which is equal to
;    ;;    the new method (according to METHOD-EQUAL).  In this case, we
;    ;;    replace the existing method with the new one.
;    ;;  - We just add the new method to discriminator-methods by pushing
;    ;;    it onto that list.
;    (unless (memq method methods)
;      (do* ((tail (discriminator-methods discriminator) (cdr tail))
;	    (existing-method (car tail) (car tail)))
;	   ((cond ((null existing-method)		 
;		   (push method (discriminator-methods discriminator)))
;		  ((method-equal existing-method type-specs options)
;		   (remove-method discriminator existing-method)
;		   (return (add-method discriminator method))))
;	    
;	    (when (method-causes-combination-p method)	         ;NOT part of
;	      (pushnew method (methods-combine-p discriminator)));standard
;						                 ;protocol.
;	    (dolist (argument-specifier type-specs)
;	      (add-method-on-argument-specifier discriminator
;						method
;						argument-specifier)))
;	()))
    (pushnew method (discriminator-methods discriminator))
    (dolist (argument-specifier type-specs)
      (add-method-on-argument-specifier discriminator
					method
					argument-specifier)))
    (discriminator-changed discriminator method t)
    (update-pretty-arglist discriminator method)	;NOT part of
						        ;standard protocol.
    ())


(defmeth remove-named-method (discriminator-name
			      argument-specifiers
			      &optional extra)
  (let ((discriminator ())
	(method ()))
    (cond ((null (setq discriminator (discriminator-named
				       discriminator-name)))
	   (error "There is no discriminator named ~S." discriminator-name))
	  ((null (setq method (find-method discriminator
					   argument-specifiers 
					   extra
					   t)))
	   (error "There is no method for the discriminator ~S~%~
                   which matches the argument-specifiers ~S."
		  discriminator
		  argument-specifiers))
	  (t
	   (remove-method discriminator method)))))

(defmeth remove-method ((discriminator basic-discriminator) method)
  (setf (method-discriminator method) nil)
  (setf (discriminator-methods discriminator)
	(delq method (discriminator-methods discriminator)))
  (dolist (type-spec (method-type-specifiers method))
    (remove-method-on-argument-specifier discriminator method type-spec))
  (discriminator-changed discriminator method nil)
  discriminator)



(defmeth add-method-on-argument-specifier
	 ((discriminator essential-discriminator)
	  (method essential-method)
	  argument-specifier)
  (ignore method)
  (when (classp argument-specifier)
    (pushnew method
	     (class-direct-methods argument-specifier))
    ;; This is a bug.  This needs to be split up into a method on
    ;; essential class and a method on class or something.
    (when (methods-combine-p discriminator)
      (pushnew discriminator
	       (class-discriminators-which-combine-methods
		 argument-specifier)))))

(defmeth remove-method-on-argument-specifier
	 ((discriminator essential-discriminator)
	  (method essential-method)
	  argument-specifier)
  (ignore method)
  (when (classp argument-specifier)
    (setf (class-direct-methods argument-specifier)
	  (delq method
		(class-direct-methods argument-specifier)))
    (when (methods-combine-p discriminator)
      (setf (class-discriminators-which-combine-methods
	      argument-specifier)
	    (delq discriminator
		  (class-discriminators-which-combine-methods
		    argument-specifier))))))


(defun make-specializable (function-name &rest options)
  (when options (setq options (list* ':allow-other-keys t options)))
  (keyword-bind ((arglist nil arglist-specified-p)
		 (discriminator-class 'discriminator)
		 (dispatch nil dispatch-p))
		options
    (cond ((not (null arglist-specified-p)))
	  ((fboundp 'function-arglist)
	   ;; function-arglist exists, get the arglist from it.
	   ;; Note: the funcall of 'function-arglist prevents
	   ;;       compiler warnings at least in some lisps.
	   (setq arglist (funcall 'function-arglist function-name)))
	  ((fboundp function-name)
	   (error
	     "The :arglist argument to make-specializable was not supplied~%~
              and there is no version of FUNCTION-ARGLIST defined for this~%~
              port of Portable CommonLoops.~%~
              You must either define a version of FUNCTION-ARGLIST (which~%~
              should be easy), and send it off to the Portable CommonLoops~%~
              people or you should call make-specializable again with the~%~
              function's arglist as its second argument.")))
    (setq dispatch
	  (if dispatch-p
	      (iterate ((disp in dispatch))
		(unless (memq disp arglist)
		  (error "There is a symbol in the :dispatch argument (~S)~%~
                          which isn't in the arglist."))
		(collect (position disp arglist)))
	      :default))
    (let ((discriminator-class-object
	    (if (classp discriminator-class)
		discriminator-class
		(class-named discriminator-class t)))
	  (discriminator nil))
      (if (null discriminator-class-object)
	  (error
	    "The :DISCRIMINATOR-CLASS argument to make-specializable is ~S~%~
             but there is no class by that name."
	    discriminator-class)
	  (setq discriminator             
		(apply #'make discriminator-class-object
		       :name function-name
		       :dispatch-order dispatch
		       options)))
;     (setf (function-pretty-arglist function-name) arglist)
      (if arglist-specified-p
	  (put-slot-always discriminator 'pretty-arglist arglist)
	  (remove-dynamic-slot discriminator 'pretty-arglist))
      (setf (discriminator-named function-name) discriminator)
      (when (fboundp function-name)
	(add-named-method (class-prototype (class-named 'discriminator))
			  (class-prototype (class-named 'method))
			  function-name
			  arglist
			  ()
			  ()
			  (symbol-function function-name)))
      discriminator)))





(defun update-pretty-arglist (discriminator method)
  (setf (function-pretty-arglist
	  (or (discriminator-name discriminator)
	      (discriminator-discriminating-function discriminator)))
	(or (get-slot-using-class (class-of discriminator) discriminator
				  'pretty-arglist t ())
	    (method-arglist method))))

(defmeth discriminator-pretty-arglist ((discriminator basic-discriminator))
  (or (get-slot-using-class (class-of discriminator) discriminator
			    'pretty-arglist t ())
      (let ((method (or (discriminator-default-method discriminator)
			(car (discriminator-methods discriminator)))))
	(and method (method-arglist method)))))

(defmeth ensure-selector-specializable ((proto-discriminator
					   essential-discriminator)
					 selector arglist)
  (let ((discriminator (discriminator-named selector)))
    (cond ((not (null discriminator)) discriminator)
          ((or (not (fboundp selector))
               (eq *error-when-defining-method-on-existing-function*
		   'bootstrapping))
           (setf (discriminator-named selector)
                 (make (class-of proto-discriminator) :name selector)))
          ((null *error-when-defining-method-on-existing-function*)
           (make-specializable selector
			       :arglist arglist
			       :discriminator-class (class-of
						      proto-discriminator))
           (discriminator-named selector))
          (t
           (error "Attempt to add a method to the lisp function ~S without~%~
                   first calling make-specializable.  Before attempting to~
                   define a method on ~S~% you should evaluate the form:~%~
                   (~S '~S)"
                  selector selector 'make-specializable selector)))))

(defmeth find-method (discriminator type-specifiers options &optional parse)
  (iterate ((method in (discriminator-methods discriminator)))
    (when (method-equal method
			(if parse
			    (parse-type-specifiers discriminator
						   method
						   type-specifiers)
			    type-specifiers)
			options)
      (return method))))

(defmeth method-equal ((method basic-method) argument-specifiers options)
  (and (equal options (method-options method))
       (equal argument-specifiers (method-type-specifiers method))))


(defmeth discriminator-default-method ((discriminator essential-discriminator))
  (find-method discriminator () ()))

(defmeth install-discriminating-function ((discriminator
					    essential-discriminator)
					  where
					  function
					  &optional inhibit-compile-p)
  (ignore discriminator)
  (check-type where symbol "a symbol other than NIL")
  (check-type function function "a funcallable object")
  
  (when (and (listp function)
	     (eq (car function) 'lambda)
	     (null inhibit-compile-p))
    (setq function (compile nil function)))

  (if where
      (setf (symbol-function where) function)
      (setf (discriminator-discriminating-function discriminator) function)))


  ;;   
;;;;;; Discriminator-Based caching.
  ;;
;;; Methods are cached in a discriminator-based cache.  The cache is an N-key
;;; cache based on the number of specialized arguments the discriminator has.
;;; As yet the size of the cache does not change statically or dynamically.
;;; Because of this I allow myself the freedom of computing the mask at
;;; compile time and not even storing it in the discriminator.

(defvar *default-discriminator-cache-size* 8)

(defun make-discriminator-cache (&optional
				  (size *default-discriminator-cache-size*))
  (make-memory-block size))

(defun make-discriminator-cache-mask (discriminator-cache
				      no-of-specialized-args)
  (make-memory-block-mask (memory-block-size discriminator-cache)
                          (+ no-of-specialized-args 1)))

(defmeth flush-discriminator-caches ((discriminator essential-discriminator))
  (let ((cache (discriminator-cache discriminator)))
    (when cache (clear-memory-block (discriminator-cache discriminator) 0))))

(defmeth initialize-discriminator-cache ((self essential-discriminator)
                                            no-of-specialized-args)
  (ignore no-of-specialized-args)
  (unless (discriminator-cache self)
    (setf (discriminator-cache self) (make-discriminator-cache))))

(defmacro discriminator-cache-offset (mask &rest classes)
  `(logand ,mask
           ,@(iterate ((class in classes))
	       (collect `(object-cache-no ,class ,mask)))))

(defmacro discriminator-cache-entry (cache offset offset-from-offset)
  `(memory-block-ref ,cache (+ ,offset ,offset-from-offset)))

(defmacro cache-method (cache mask method-function &rest classes)
  `(let* ((.offset. (discriminator-cache-offset ,mask ,@classes)))
     ;; Once again, we have to endure a little brain damage because we can't
     ;; count on having without-interrupts.  I suppose the speed loss isn't
     ;; too significant since this is only when we get a cache miss.
     (setf (discriminator-cache-entry ,cache .offset. 0) nil)
     ,@(iterate ((class in (cdr classes)) (key-no from 1))
         (collect `(setf (discriminator-cache-entry ,cache .offset. ,key-no)
			 ,class)))
     (prog1
       (setf (discriminator-cache-entry ,cache .offset. ,(length classes))
	     ,method-function)
       (setf (discriminator-cache-entry ,cache .offset. 0) ,(car classes)))))

(defmacro cached-method (var cache mask &rest classes)
  `(let ((.offset. (discriminator-cache-offset ,mask . ,classes)))
     (and ,@(iterate ((class in classes) (key-no from 0))
              (collect
                `(eq (discriminator-cache-entry ,cache .offset. ,key-no)
		     ,class)))
          (setq ,var (discriminator-cache-entry ,cache
						.offset.
						,(length classes)))
          t)))

(defmeth make-caching-discriminating-function (discriminator lookup-function
							      cache
							      mask)
  (multiple-value-bind (required restp specialized-positions)
      (compute-discriminating-function-arglist-info discriminator)
    (funcall (get-templated-function-constructor
	       'caching-discriminating-function
	       required
	       restp
	       specialized-positions
	       lookup-function)
             discriminator cache mask)))

(defun make-checking-discriminating-function (discriminator method-function
                                                            type-specs
							    default-function)
  (multiple-value-bind (required restp)
      (compute-discriminating-function-arglist-info discriminator)
    (let ((check-positions
	    (iterate ((type-spec in type-specs)
		      (pos from 0))
	      (collect (and (neq type-spec 't) pos)))))
      (apply (get-templated-function-constructor
	       'checking-discriminating-function
	       required
	       restp
	       (if default-function t nil)
	       check-positions)
             discriminator method-function default-function type-specs))))


  ;;   
;;;;;; 
  ;;   

(defvar *always-remake-discriminating-function* nil)

(defmeth make-discriminating-function ((discriminator
					 essential-discriminator))
  (let ((default (discriminator-default-method discriminator))
        (methods (discriminator-methods discriminator)))
    (cond ((null methods)
	   (make-no-methods-discriminating-function discriminator))
	  ((and default (null (cdr methods)))
           (make-default-method-only-discriminating-function discriminator))
          ((or (and default (null (cddr methods)))
	       (and (null default) (null (cdr methods))))
           (make-single-method-only-discriminating-function discriminator))
          ((every #'(lambda (m)
                      (classical-type-specifiers-p
			(method-type-specifiers m)))
                  methods)
           (make-classical-methods-only-discriminating-function
	     discriminator))
          (t
           (make-multi-method-discriminating-function discriminator)))))

(defmeth make-no-methods-discriminating-function (discriminator)
  (install-discriminating-function
    discriminator
    (discriminator-name discriminator)
    #'(lambda (&rest ignore)
	(error "There are no methods on the discriminator ~S,~%~
                so it is an error to call it."
	       discriminator))))

(defmeth make-default-method-only-discriminating-function
	 ((self essential-discriminator))
  (install-discriminating-function
    self
    (discriminator-name self)
    (method-function (discriminator-default-method self))))

(defmeth make-single-method-only-discriminating-function
	  ((self essential-discriminator))
  (let* ((methods (discriminator-methods self))
	 (default (discriminator-default-method self))
	 (method (if (eq (car methods) default)
		     (cadr methods)
		     (car methods)))
         (method-type-specifiers (method-type-specifiers method))
         (method-function (method-function method)))
    (install-discriminating-function
      self
      (discriminator-name self)
      (make-checking-discriminating-function
	self
	method-function
	method-type-specifiers
	(and default (method-function default))))))

(defmeth make-classical-methods-only-discriminating-function
	  ((self essential-discriminator))
  (initialize-discriminator-cache self 1)
  (let ((default-method (discriminator-default-method self))
	(methods (discriminator-methods self)))
    (setf (discriminator-classical-method-table self)
	  (cons (and default-method (method-function default-method))
		(iterate ((method in methods))
		  (unless (eq method default-method)
		    (collect (cons (car (method-type-specifiers method))
				   (method-function method))))))))
  (let* ((cache (discriminator-cache self))
	 (mask (make-discriminator-cache-mask cache 1)))
    (install-discriminating-function
      self
      (discriminator-name self)
      (make-caching-discriminating-function
	self 'lookup-classical-method cache mask))))

(defun lookup-classical-method (discriminator class)
  ;; There really should be some sort of more sophisticated protocol going
  ;; on here.  Compare type-specifiers and all that.
  (let* ((classical-method-table
	   (get-slot--class discriminator 'classical-method-table)))
    (or (iterate ((super in (get-slot--class class 'class-precedence-list)))
          (let ((hit (assq super (cdr classical-method-table))))
            (when hit (return (cdr hit)))))
	(car classical-method-table))))

(defmeth make-multi-method-discriminating-function
	  ((self essential-discriminator))
  (multiple-value-bind (required restp specialized)
      (compute-discriminating-function-arglist-info self)
    (ignore required restp)
    (initialize-discriminator-cache self (length specialized))
    (let* ((cache (discriminator-cache self))
	   (mask (make-discriminator-cache-mask cache (length specialized))))
      (install-discriminating-function
	self
	(discriminator-name self)
	(make-caching-discriminating-function
	  self 'lookup-multi-method cache mask)))))

(defvar *lookup-multi-method-internal*
	(make-array (min 256. call-arguments-limit)))

(defun lookup-multi-method-internal (discriminator classes)
  (let* ((methods (discriminator-methods discriminator))
	 (cpls *lookup-multi-method-internal*)
	 (order (get-slot--class discriminator 'dispatch-order))
         (most-specific-method nil)
         (most-specific-type-specs ())
	 (type-specs ()))
    ;; Put all the class-precedence-lists in a place where we can save
    ;; them as we look through all the methods.
    (without-interrupts
      (iterate ((class in classes)
		(i from 0))
	(setf (svref cpls i) (get-slot--class class 'class-precedence-list)))
      (dolist (method methods)
	(setq type-specs (get-slot--class method 'type-specifiers))
	(when (iterate ((type-spec in  type-specs)
			(i from 0))
		(or (eq type-spec 't)
		    (memq type-spec (svref cpls i))
		    (return nil))
		(finally (return t)))
	  (if (null most-specific-method)
	      (setq most-specific-method method
		    most-specific-type-specs type-specs)
	      (case (compare-type-specifier-lists
		      most-specific-type-specs type-specs nil
		      () classes order)
		(2 (setq most-specific-method method
			 most-specific-type-specs type-specs))
		(1))))))
    (or most-specific-method
	(discriminator-default-method discriminator))))

(defun lookup-multi-method (discriminator &rest classes)
  (declare (inline lookup-multi-method-internal))
  (let ((method (lookup-multi-method-internal discriminator classes)))
    (and method (method-function method))))

(defun lookup-method (discriminator &rest classes)
  (declare (inline lookup-multi-method-internal))
  (lookup-multi-method-internal discriminator classes))

  ;;   
;;;;;; Code for parsing arglists (in the usual case).
  ;;   (when discriminator is class DISCRIMINATOR and method is class METHOD)
;;;
;;; arglist-type-specifiers
;;; Given an arglist this returns its type-specifiers.  Trailing T's (both
;;; implicit and explicit) are dropped.  The type specifiers are returned as
;;; they are found in the arglist, they are not parsed into internal
;;; type-specs.
;;;
(defmeth arglist-type-specifiers ((proto-disc basic-discriminator)
				  (proto-meth basic-method)
				  arglist)
  (let ((arg (car arglist)))
    (and arglist
         (not (memq arg '(&optional &rest &key &aux)))  ;Don't allow any
                                                        ;type-specifiers
	                                                ;after one of these.
         (let ((tail (arglist-type-specifiers proto-disc
					      proto-meth
					      (cdr arglist)))
               (type-spec (and (listp arg) (cadr arg))))
           (or (and tail (cons (or type-spec 't) tail))
               (and type-spec (cons type-spec ())))))))

;;; arglist-without-type-specifiers
;;; Given an arglist remove the type specifiers.
;;; 
(defmeth arglist-without-type-specifiers ((proto-disc basic-discriminator)
					  (proto-meth basic-method)
					  arglist)
  (let ((arg (car arglist)))
    (and arglist
         (if (memq arg '(&optional &rest &key &aux))    ;don't allow any
                                                        ;type-specifiers
                                                        ;after one of these.
             arglist
             (cons (if (listp arg) (car arg) arg)
                   (arglist-without-type-specifiers proto-disc
						    proto-meth
						    (cdr arglist)))))))

(defmeth arglist-args ((discriminator-class basic-discriminator)
		       (method-class basic-method)
		       arglist)
  (and arglist
       (cond ((eq (car arglist) '&aux) ())
             ((memq (car arglist) '(&optional &rest &key))
              (arglist-args discriminator-class method-class (cdr arglist)))
             (t
              ;; This plays on the fact that no type specifiers are allowed
	      ;; on arguments that can have default values.
              (cons (if (listp (car arglist)) (caar arglist) (car arglist))
                    (arglist-args discriminator-class
				  method-class
				  (cdr arglist)))))))

(defmeth parse-type-specifiers ((proto-discriminator basic-discriminator)
				(proto-method basic-method)
				type-specifiers)
  (iterate ((type-specifier in type-specifiers))
    (collect (parse-type-specifier proto-discriminator
				   proto-method
				   type-specifier))))

(defmeth parse-type-specifier ((proto-discriminator basic-discriminator)
                                (proto-method basic-method)
                                type-specifier)
  (ignore proto-discriminator proto-method)
  (cond ((eq type-specifier 't) 't)
        ((symbolp type-specifier)
         (or (class-named type-specifier nil)
             (error
	       "~S used as a type-specifier, but is not the name of a class."
	       type-specifier)))
        ((classp type-specifier) type-specifier)
        (t (error "~S is not a legal type-specifier." type-specifier))))

(defmeth unparse-type-specifiers ((method essential-method))
  (iterate ((parsed-type-spec in (method-type-specifiers method)))
    (collect (unparse-type-specifier method parsed-type-spec))))

(defmeth unparse-type-specifier ((method essential-method) type-spec)
  (ignore method)
  (if (classp type-spec)
      (class-name type-spec)
      type-spec))

(defun classical-type-specifiers-p (typespecs)
  (or (null typespecs)
      (and (classp (car typespecs))
           (null (cdr typespecs)))))

;;;
;;; Compute various information about a discriminator's arglist by looking at
;;; the argument lists of the methods.  The hair for trying not to use &rest
;;; arguments lives here.
;;;  The values returned are:
;;;    number-of-required-arguments
;;;       the number of required arguments to this discrimator's
;;;       discriminating function
;;;    &rest-argument-p
;;;       whether or not this discriminator's discriminating
;;;       function takes an &rest argument.
;;;    specialized-argument-positions
;;;       a list of the positions of the arguments this discriminator
;;;       specializes (e.g. for a classical discrimator this is the
;;;       list: (1)).
;;;
;;; As usual, it is legitimate to specialize the -internal function that is
;;; why I put it there, since I certainly could have written this more
;;; efficiently if I didn't want to provide that extensibility.
;;; 
(defmeth compute-discriminating-function-arglist-info
	 ((discriminator essential-discriminator)
	  &optional (methods () methods-p))
  (declare (values number-of-required-arguments
                   &rest-argument-p
                   specialized-argument-postions))
  (unless methods-p
    (setq methods (discriminator-methods discriminator)))
  (let ((number-required nil)
        (restp nil)
        (specialized-positions ()))
    (iterate ((method in methods))
      (multiple-value-setq (number-required restp specialized-positions)
        (compute-discriminating-function-arglist-info-internal
	  discriminator method number-required restp specialized-positions)))
    (values number-required restp (sort specialized-positions #'<))))

(defmeth compute-discriminating-function-arglist-info-internal
	 ((discriminator essential-discriminator)
	  (method essential-method)
	  number-of-requireds restp specialized-argument-positions)
  (ignore discriminator)
  (let ((requireds 0))
    ;; Go through this methods arguments seeing how many are required,
    ;; and whether there is an &rest argument.
    (iterate ((arg in (method-arglist method)))
      (cond ((eq arg '&aux) (return))
            ((memq arg '(&optional &rest &key))
             (return (setq restp t)))
	    ((memq arg lambda-list-keywords))
            (t (incf requireds))))
    ;; Now go through this method's type specifiers to see which
    ;; argument positions are type specified.  Treat T specially
    ;; in the usual sort of way.  For efficiency don't bother to
    ;; keep specialized-argument-positions sorted, rather depend
    ;; on our caller to do that.
    (iterate ((type-spec in (method-type-specifiers method))
              (pos from 0))
      (unless (eq type-spec 't)
	(pushnew pos specialized-argument-positions)))
    ;; Finally merge the values for this method into the values
    ;; for the exisiting methods and return them.  Note that if
    ;; num-of-requireds is NIL it means this is the first method
    ;; and we depend on that.
    (values (min (or number-of-requireds requireds) requireds)
            (or restp
		(and number-of-requireds (/= number-of-requireds requireds)))
            specialized-argument-positions)))

(defun make-discriminating-function-arglist (number-required-arguments restp)
  (iterate ((i from 0 below number-required-arguments))
    (collect (intern (format nil "Discriminating Function Arg ~D" i)))
    (finally (when restp
               (collect '&rest)
               (collect (intern "Discriminating Function &rest Arg"))))))

(defmeth compare-methods (discriminator method-1 method-2)
  (ignore discriminator)
  (let ((compare ()))
    (iterate ((ts-1 in (method-type-specifiers method-1))
	      (ts-2 in (method-type-specifiers method-2)))
      (cond ((eq ts-1 ts-2) (setq compare '=))
	    ((eq ts-1 't)   (setq compare method-2))
	    ((eq ts-2 't)   (setq compare method-1))	    
	    ((memq ts-1 (class-class-precedence-list ts-2))
	     (setq compare method-2))
	    ((memq ts-2 (class-class-precedence-list ts-1))
	     (setq compare method-1))
	    (t (return nil)))
      (finally (return compare)))))

  ;;   
;;;;;; Comparing type-specifiers, statically or wrt an object.
  ;;
;;; compare-type-specifier-lists compares two lists of type specifiers
;;; compare-type-specifiers compare two type specifiers
;;; If static-p it t the comparison is done statically, otherwise it is
;;; done with respect to object(s).  The value returned is:
;;;    1    if type-spec-1 is more specific
;;;    2    if type-spec-2 is more specific
;;;    =    if they are equal
;;;    NIL  if they cannot be disambiguated
;;;
(defun compare-type-specifier-lists (type-spec-list-1
				     type-spec-list-2
				     staticp
				     args
				     classes
				     order)
  (when (or type-spec-list-1 type-spec-list-2)
    (ecase (compare-type-specifiers (or (car type-spec-list-1) t)
                                    (or (car type-spec-list-2) t)
                                    staticp
                                    (car args)
                                    (car classes))
      (1 '1)
      (2 '2)
      (= (if (eq order :default)
	     (compare-type-specifier-lists (cdr type-spec-list-1)
					   (cdr type-spec-list-2)
					   staticp
					   (cdr args)
					   (cdr classes)
					   order)
	     (compare-type-specifier-lists (nth (car order) type-spec-list-1)
					   (nth (car order) type-spec-list-2)
					   staticp
					   (cdr args)
					   (cdr classes)
					   (cdr order))))
	    
      (nil
        (unless staticp
          (error "The type specifiers ~S and ~S can not be disambiguated~
                  with respect to the argument: ~S"
                 (or (car type-spec-list-1) t)
                 (or (car type-spec-list-2) t)
                 (car args)
                 (car classes)))))))

(defun compare-type-specifiers (type-spec-1 type-spec-2 staticp arg class)
  (cond ((equal type-spec-1 type-spec-2) '=)
        ((eq type-spec-2 t) '1)
        ((eq type-spec-1 t) '2)
        ((and (classp type-spec-1) (classp type-spec-2))
;        (if staticp
;            (if (common-subs type-spec-1 type-spec-2)
;                nil
;                (let ((supers (common-supers type-spec-1 type-spec-2)))
;                  (cond ((cdr supers) nil)
;                        ((eq (car supers) type-spec-1) '2)
;                        ((eq (car supers) type-spec-2) '1)
;                        (t 'disjoint))))
             (iterate ((super in (class-class-precedence-list (or class (class-of arg)))))
               (cond ((eq super type-spec-1)
                      (return '1))
                     ((eq super type-spec-2)
                      (return '2)))))
;)
        (t
         (compare-complex-type-specifiers type-spec-1 type-spec-2 staticp arg class))))

(defun compare-complex-type-specifiers (type-spec-1 type-spec-2 static-p arg class)
  (ignore type-spec-1 type-spec-2 static-p arg class)
  (error "Complex type specifiers are not yet supported."))

(defmeth no-matching-method (discriminator)
  (let ((class-of-discriminator (class-of discriminator)))
    (if (eq (class-of class-of-discriminator) (class-named 'class))
        ;; The meta-class of the discriminator is class, we can get at
        ;; it's name slot without doing any method lookup.
        (let ((name (get-slot--class discriminator 'name)))
          (if (and name (symbolp name))
              (error "No matching method for: ~S." name)
              (error "No matching method for the anonymous discriminator: ~S."
                     discriminator)))
        (error "No matching method for the discriminator: ~S." discriminator))))
  ;;   
;;;;;; Optimizing GET-SLOT
  ;;   

(defmeth method-argument-class ((method basic-method) argument)
  (let* ((arglist (method-arglist method))
         (position (position argument arglist)))
    (and position (nth position (method-type-specifiers method)))))


(defmeth optimize-get-slot ((class basic-class)
			    form)
  (declare (ignore class))
  (cons 'get-slot--class (cdr form)))

(defmeth optimize-setf-of-get-slot ((class basic-class)
				    form)
  (declare (ignore class))
  (cons 'put-slot--class (cdr form)))
@EOF
if test "`wc -lwc <methods.l`" != '   1118   3675  42045'
then
	echo ERROR: wc results of methods.l are `wc -lwc <methods.l` should be 1118   3675  42045
fi

chmod 755 methods.l

exit 0