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

call-next-method incoherency



Here are some arguments from JonL which I find quite persuasive.
Before I saw these I was just going to go with #1 since that's
what all the respondents had said, but now I am reconfirmed in my
belief that #3 is the best option.  Did the people who suggested
#1 base their suggestion on careful thought, or just pick that one
because it seemed easiest or was first on the list?  If there are
good arguments for #1 I'd like to hear them.

#1 smacks of overloading a communication channel.  Some lusers out there
   will come to depend on finding out the method-combination mismatch
   error by placing obscure methods on NO-NEXT-METHOD, so we will never
   be able to correct this wort once it gets in.

#4 smacks of overkill; a piece of syntax at the same level as everything
   else in method combination  to cover an incredibly obscure problem that 
   almost no one will run into.  Why clutter up the spec.  Besides, whole
   method groups might be too coarse a sieve to strain out the contexts
   under which you want to proscribe CALL-NEXT-METHOD.

#3 is a very logical extension of the meaning of CALL-METHOD as spelled
   out in 88-002R p.2-11.  CALL-METHOD should bear the burden, since it 
   is the interface between method-combination and CALL-NEXT-METHOD.  I 
   suspect some existing implementations (e.g. PCL) would require more of 
   a change to do it this way than by #1, but not a radical change.

#2 is just a variant of #3, but the syntax is more "special case", rather
   than the "natural extesion" of #3.  Providing a null list for the
   next-methods argument is a fine way to say "any use of CALL-NEXT-METHOD 
   will simply call NO-NEXT-METHD";  the natural way to differentiate this
   case from a control-error case is to _not_ provide the next-methods
   argument at all.  Thus #3 is preferable.

The argument would be compelling if you could show a way to model the 
prohibitions in standard-method-combination using this #3 approach 
(i.e., can't use CALL-NEXT-METHOD in :before or :after methods, but can 
use it in primary and :around).

That's the end of the quotation from JonL, the rest is my response:

 From the documentation examples, here is the existing definition of
standard method combination:

;The default method-combination technique
(define-method-combination standard ()
	((around (:around))
	 (before (:before))
	 (primary () :required t)
	 (after (:after)))
  (flet ((call-methods (methods)
	   (mapcar #'(lambda (method)
		       `(call-method ,method ()))
		   methods)))
    (let ((form (if (or before after (rest primary))
		    `(multiple-value-prog1
		       (progn ,@(call-methods before)
			      (call-method ,(first primary)
					   ,(rest primary)))
		       ,@(call-methods (reverse after)))
		    `(call-method ,(first primary) ()))))
      (if around
	  `(call-method ,(first around)
			(,@(rest around)
			 (make-method ,form)))
	  form))))

and here is the compelling modified version for the #3 approach:

;The default method-combination technique
(define-method-combination standard ()
	((around (:around))
	 (before (:before))
	 (primary () :required t)
	 (after (:after)))
  (flet ((call-methods (methods)
	   (mapcar #'(lambda (method)
		       `(call-method ,method))
		   methods)))
    (let ((form (if (or before after (rest primary))
		    `(multiple-value-prog1
		       (progn ,@(call-methods before)
			      (call-method ,(first primary)
					   ,(rest primary)))
		       ,@(call-methods (reverse after)))
		    `(call-method ,(first primary) ()))))
      (if around
	  `(call-method ,(first around)
			(,@(rest around)
			 (make-method ,form)))
	  form))))

Only one line is changed.