[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: moderating clos mailing list

    Date: Wed, 16 Nov 88 21:52:12 EST
    From: Michael Sokolov <sokolov@whitechapel.media.mit.edu>

	    I agree that most of the discussion on ERNIE vs. PCL has been
    unsubstantiated name-calling, but it does raise an interesting issue:
    namely, the issue of type declarations. There are obviously going to
    be cases where types will be known at compile time and it will be
    optimal to compile out the method-decoding and class-specialization:
    CLOS doesn't seem to address this.

Actually, CLOS does address this in two distinct and important ways.

1) Under certain compiler optimizations, I think you can expect a CLOS
implementation to optimize out method lookup in code like the following.

(defclass foo () ())
(defclass bar () ())

(defmethod doit ((f foo)) ...)
(defmethod doit ((b bar)) ...)

.. (progn (dolist (f *the-foos*) (doit (the foo f)))
          (dolist (b *the-bars*) (doit (the bar b)))) ..

I think you can also expect code like this to optimize out the method
lookup for calls to the generic function inner.

(defmethod outer ((f foo)) .. (inner f) ..)
(defmethod outer ((b bar)) .. (inner b) ..)

(defmethod inner ((f foo)) ..)
(defmethod inner ((b bar)) ..)

2) Using the metaobject protocol, you can do certain optimizations by
hand.  For example, Mike Thome mentioned in his message that he replaced
all the one method generic functions with ordinary functions.  When he
did this, he was assuming the code had no bugs so that whenever that
generic function was called, its only method was appropriate.  Here is
PCL code that does that by direct manipulation of the metaobjects.  It
has the advantage that you can switch the optimization on and off for
already loaded code.

To use it you first call gather-generic-functions to collect up the
generic functions that are in your package.  Then
make-generic-functions-unsafe converts them to use this optimization.
make-generic-functions-safe converts them back.

(in-package 'pcl)

(defclass unsafe-gf (standard-generic-function)
  (:metaclass funcallable-standard-class))

(defmethod compute-discriminator-code ((gf unsafe-gf))
  (let ((methods (generic-function-methods gf)))
    (if (and methods
	     (null (cdr methods))
	     (null (every #'(lambda (m)
			      (or (standard-reader-method-p m)
				  (standard-writer-method-p m)))
	(method-function (car methods))

(defvar *generic-functions* ())

(defun gather-generic-functions (package)
  (do-symbols (symbol package)
    (let ((fn nil))
      (when (and (fboundp symbol)
		 (setq fn (symbol-function symbol))
		 (pcl::generic-function-p fn))
	(pushnew fn *generic-functions*)))))

(defun make-generic-functions-unsafe ()
  (let ((unsafe-class (find-class 'unsafe-gf)))
    (dolist (gf *generic-functions*)
      (change-class gf unsafe-class)
      (update-discriminator-code gf))))

(defun make-generic-functions-safe ()
  (let ((safe-class (find-class 'standard-generic-function)))
    (dolist (gf *generic-functions*)
      (change-class gf safe-class)
      (update-discriminator-code gf))))