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

call-method proposal



I spent some time thinking about how to solve the problem with
make-method-call and concluded that make-method-call was a really
complex little bugger.  I have come up with a mechanism I believe is
simpler, on first examination it appears to be missing the single method
optimization but I believe that can be fixed quite easily.

This description is not entirely adequate, but I hope its enough to
convey the flavor of this proposal.

This proposal uses two lexical macros, CALL-METHOD and EFFECTIVE-METHOD.
These macros are lexically bound within the scope of an effective method
body.  That means that the body of define-method-combination is allowed
to return code that uses these macros.  Code walkers can understand
these macros quite easily, I believe their semantics is also easier for
programmers to understand.

The differences between this and make-method-call in the spec are:

 - these are lexical macros
 - the functionality of automatically converting lists to
   combined methods provided by make-method-call is not
   provided by call-method.  Instead, the effective method
   lexical macro must be used to declare that a form is
   itself an effective method being used in the call-next-method
   list.
 - call-method accepts two required arguments.  The method to
   call is the first argument.  The next methods accesible from
   that method is the second argument.
 - support for :operation and :identity-with-one-argument is
   missing.  I believe this makes things simpler.  I also believe
   we can get that optimization back quite easily.

The biggest difference is that I find this conceptually simpler to
understand.  When I see call-method, I don't have to think about the
three different forms the first argument to make-method-call can have, I
know the first argument must be a method.  I know the second argument
must be a list of methods or effective-method forms.

Here are implementations of standard and and method combination written
using this mechanism.  I have read them over, I believe they are right,
but I don't have an implementation of this so I can't be sure.

(define-method-combination standard ()
        ((around (:around))
	 (before (:before))
	 (primary () :required t)
	 (after (:after)))
  (let ((effective
	  ;; This is the real method that gets run once all of the
	  ;; :around methods have call-next-method'ed to get to it.
	  `(effective-method
	     (progn ,@(mapcar #'(lambda (m) `(call-method ,m ())) before))
	     (call-method ,(car primary) ,(cdr primary))
	     (progn ,@(mapcar #'(lambda (m) `(call-method ,m ())) after)))))
    (if around
	`(call-method ,(car around)
		      ,(append (cdr around) (list effective)))
	`(call-method ,effective ()))))

(define-method-combination and (&optional (order ':most-specific-first))
        ((around (:around))
	 (primary (and) :order order :required t))
  (let ((effective
	  `(effective-method
	     (and (mapcar #'(lambda (m) `(call-method ,m ()))
			  primary)))))
    (if around
	`(call-method ,(car around)
		      ,(append (cdr around) (list effective)))
	`(call-method ,effective))))
-------