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

call-method proposal prime prime

Pavel pointed out that I lost while trying to compensate for previous
lossage.  At least I know Pavel is reading these messages.  This message
entirely supersedes the messages I sent earlier.

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
 - 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.
                    ,@(mapcar #'(lambda (m) `(call-method ,m ()))
                    (call-method ,(car primary) ,(cdr primary)))
                 ,@(mapcar #'(lambda (m) `(call-method ,m ()))
                           (reverse 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
             (and (mapcar #'(lambda (m) `(call-method ,m ()))
    (if around
        `(call-method ,(car around)
                      ,(append (cdr around) (list effective)))
        `(call-method ,effective))))