[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: call-method ??????
- To: lafourca@imag.fr (mathieu Lafourcade)
- Subject: Re: call-method ??????
- From: bill@cambridge.apple.com (Bill St. Clair)
- Date: Fri, 30 Oct 1992 08:13:54 -0600
- Cc: Ranson <ranson@LANNION.cnet.fr>, info-mcl
>Date: Thu, 29 Oct 1992 10:42:32 +0100
>To: info-mcl@cambridge.apple.com
>From: lafourca@imag.fr (mathieu Lafourcade)
>Subject: call-method ??????
>
>Following my last request about a method dispatching, it appears that it
>could be nice to define a function (or macro) that could specify a call to
>a method of an arbitrary class.
>
>BUT....
>
>I have a big problem with CALL-METHOD method next-method-list.
>In CLtL p 817 it is said :
>[...] It can be used only within an affetive method form, for the name
>call-method is defined only within the lexical scope of such a form.
>The macro call-method invokes the specified method, supplying it with
>arguments and with definitions for call-next-method and for next-method-p.
>The arguments are the arguments that were supplied to the effective method
>form containing the invocation of call-method. [...]
>
>First:
> call-method is defined as it in MCl, but as ccl::%call-method,
>ccl::%%call-method, ccl::%call-method*, ccl::%%call-method*
> Which one to choose ?
>[...]
>Date: 30 Oct 92 13:46:00 GMT
>From: Ranson <ranson@LANNION.cnet.fr>
>To: info-mcl@cambridge.apple.com, lafourca@imag.fr
>Subject: Re: call-method ??????
>
>I don't have a direct answer to your question (though I wonder why you mention
>CALL-METHOD and don't use it...), but it seems to me that if you find yourself
>in such a tight corner, it means that your design does not fit in the OO model.
>Either change your design, or try to use ordinary functions instead of methods.
> Daniel.
Daniel has a good point, though he appears to misunderstand CALL-METHOD.
CALL-METHOD is only defined inside the form returned from DEFINE-METHOD-COMBINATION.
Daniel's misunderstanding is very common.
Flame on.
I have always thought that DEFINE-METHOD-COMBINATION as defined by the
CLOS standard was a crock. I think it should return a function that
invokes the methods via a CALL-METHOD function rather than returning a
form which requires invoking the compiler at method combination time.
Yes, the former is slightly slower at run time, but the latter makes it
a lot slower to "warm up" your generic functions.
Flame off.
---------------------------------------------------------------------------
MCL has four functions for calling methods functionally:
(ccl::%call-method method next-methods &rest args)
(ccl::%call-method* method next-methods args)
(ccl::%%call-method method next-methods &rest args)
(ccl::%%call-method* method next-methods args)
All four apply the METHOD to the ARGS with the given NEXT-METHODS.
The "*" versions take the args as a list.
The %% versions do not type check the METHOD or NEXT-METHODS
arguments and will likely crash if METHOD is not a method or NEXT-METHODS
is not a proper list of methods.
---------------------------------------------------------------------------
The rest of this message is not in answer to your question, but may be
of interest to DEFINE-METHOD-COMBINATION fans. I am not particularly
happy with MCL's DEFINE-METHOD-COMBINATION extensions, mostly because
of the (make-instance 'standard-method ...) form in the third
DEFINE-METHOD-COMBINATION form below, but it's the start of an idea for
a functional DEFINE-METHOD-COMBINATION definition. These extensions are
part of MCL 2.0, but may change in a future release.
---------------------------------------------------------------------------
; Here are three equivalent ways of defining AND method-combination
; They illustrate MCL's two extensions to method-combination that
; allow you to eliminate calling the compiler at method combination
; time in exchange for being slightly slower at run-time.
; Short-form
; define-method-combination-evaluator eliminates compiling effective
; methods for short-form method combination
(define-method-combination my-and :identity-with-one-argument t)
(define-method-combination-evaluator my-and (methods args)
(when methods
(loop
(if (null (cdr methods))
(return (%%call-method* (car methods) nil args)))
(unless (%%call-method* (pop methods) nil args)
(return nil)))))
; The standard form given in CLtL2
(define-method-combination my-and
(&optional (order :most-specific-first))
((around (:around))
(primary (my-and) :order order :required t))
(let ((form (if (rest primary)
`(and ,@(mapcar #'(lambda (method) `(call-method ,method ()))
primary))
`(call-method ,(first primary) ()))))
(if around
`(call-method ,(first around)
(,@(rest around)
(make-method ,form)))
form)))
; a version of the above that does not require the compiler
; at effective-method computation time.
; If the DEFINE-METHOD-COMBINATION form returns a function, the
; method-combination code will assume that it is an effective-method that
; can be applied to the args of the generic-function.
(define-method-combination my-and
(&optional (order :most-specific-first))
((around (:around))
(primary (my-and) :order order :required t))
(let ((f (if (rest primary)
#'(lambda (&rest args)
(declare (dynamic-extent args))
(let ((methods primary))
(unless (null methods)
(loop
(if (cdr methods)
(unless (%call-method* (pop methods) nil args)
(return nil))
(return (%call-method* (car methods) nil args)))))))
(if (call-next-method-p (setq primary (car primary)))
#'(lambda (&rest args)
(declare (dynamic-extent args))
(%call-method* primary nil args))
(method-function primary)))))
(if around
(let ((first (first around))
(rest (nconc (rest around)
(list (make-instance 'standard-method
:function f)))))
#'(lambda (&rest args)
(declare (dynamic-extent args))
(%call-method* first rest args)))
f)))
#|
; Some test code for the my-and method-combination
; If you reevaluate one of the method-combination defining forms above,
; make sure to reevaluate one of the defmethod forms below to cause
; the and-tester generic function to recompute its effective method.
(defgeneric and-tester (x)
(:method-combination my-and))
(defmethod and-tester my-and (x)
(print '(and-tester my-and (t)))
(values x 't))
(defmethod and-tester my-and ((x integer))
(print '(and-tester my-and (integer)))
(unless (eql x 2)
(values x 'integer)))
(defmethod and-tester my-and ((x fixnum))
(print '(and-tester my-and (fixnum)))
(unless (eql x 1)
(values x 'fixnum)))
(defmethod and-tester :around ((x fixnum))
(print '(and-tester :around (fixnum)))
(call-next-method))
(and-tester 1)
(and-tester 2)
(and-tester 3)
(and-tester (expt 2 32))
(and-tester 'foo)
|#