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

Re: Getting hold of the method object currently executed

    Date: Wed, 15 Nov 89 09:51:13 EST
    From: Martin Boyer <gamin@Moe.McRCIM.McGill.EDU>

    In Victoria Day PCL, is it possible, from the body of a method, to
    reference the method object itself?

I will divide my reply into two messages.  This message discusses the
real issue, and the "right way" to get the behavior you want.  This can
be done with or without the metaobject protocol.  By right way, I mean
what you could do without the MOP if PCL supported it or what you will
be able to do with the MOP when PCL supports it.  The "future perfect"
shall we say.

A subsequent message will talk about how to do this in Victoria Day PCL.

First, it is important to rephrase your question more precisely in terms
of the concepts that exist in CLOS.  The key point here is that method
lookup in CLOS is divided into two parts.  

  "computing the ordered list of applicable methods"

This part takes the generic function and the set of arguments and
returns a list of methods.  This list is sorted by methods specificity
with the most specific methods first.  The sorting completely ignores
any method qualifiers.

  "computing the effective method"

This takes the ordered list of applicable method and produces from them
an effective method.  In essence, this does the method combination.  The
result of this phase is a weird kind of form which uses the special
marker CALL-METHOD.  Note that CALL-METHOD is NOT A MACRO, it isn't
defined except in the body of an effective method form.

In the degenerate case where you are:

 1) using standard method combination

 2) not using :before, :after, or :around methods

 3) not using call-next-method

 (or using a method combination with equivalent behavior)

 then the effective method is always just a call to the first of
 the applicable methods.  Another way of saying this is that within
 the body of a method on the generic function foo, the following
 form always returns to the method being run:

   (car (compute-applicable-methods generic-function arglist))

 Of course, this form has the significant bug that it is slow.  It
 recomputes the method from scratch which seems unfortunate.

But, if this degenerate case is what you need, you could define a
special kind of method combination which would give you access to the
method being run:

(defvar *method-being-run*)

(define-method-combination runtime-access-to-method ()
        ((all () :required t))
  `(let ((*method-being-run* ',(car all)))
     (call-method ,(car all))))

Then you can say:

(defgeneric foo (x)
  (:method-combination runtime-access-to-method))

(defmethod foo ((b boat))
  (mumble *method-being-run*))

Because this uses a special variable, you have to be careful about
funargs in the usual way.

But, if you do want to use the full power of method combination, and
moreover you want to use pre-defined method combination types, you are
going to have to do something else.  The following would do the trick,
but is likely to have a more dramatic affect on performance than
defining a special method combination as done above.

(defmethod apply-method-function ((gf runtime-reflection-generic-function)
				  (method method)
  (let ((*method-being-run* method))
    (declare (special *method-being-run*))

(defmethod make-method-lambda ((gf runtime-reflection-generic-function)
			       (method method)
  (call-next-method gf
		    `(let ((.method-being-run. *method-being-run*))
		       (flet ((this-method () .method-being-run.))

Given these two definitions, the following works:

(defgeneric foo (x)
  (:generic-function-class runtime-reflection-generic-function))

(defmethod foo ((b boat))
  (mumble (this-method)))