Re: Two MOP usage questions
On Wed, 8 Sep 2004 00:04:17 +0200, Pascal Costanza <costanza@web.de> wrote:
> In general, DEFCLASS and DEFMETHOD should work when they are not at
> the top level. However, you probably want to have their effect
> depend on runtime properties, so this probably won't get you very
> far. On the other hand, ENSURE-CLASS and ADD-METHOD are somewhat
> complicated to use, so I suggest to first try the former and only
> switch to the latter when you actually need them. In other words, as
> soon as you feel compelled to say (EVAL `(DEFXYZ
> ... ,(some-runtime-property) ...)), you should switch to the MOP.
Yes, I forgot to mention that. If I were to use the macros I would
definitely need to use EVAL so that was another reason to investigate
the functions instead.
> ANSI specifies the effects of DEFCLASS, DEFMETHOD and the likes when
> they are not at the top level. Essentially, it specifies that there
> is no guarantee with regard to compile-time effects.
What could that be? Anything to worry about?
> Yes, this is part of the MOP specification. Usually, you don't
> create a function directly with LAMBDA, but rather use the MOP's
> MAKE-METHOD-LAMBDA. Check out the section about "Processing of the
> User Interface Macros" in AMOP, especially "The defmethod Macro" and
> "Processing Method Bodies". This gives you a pretty good idea what
> you need to do to create your own methods at run time.
Argh! I had read that the other day but skipped parts of it because I
thought it wouldn't apply in my case... :(
> LispWorks deviates with regard to the parameters a method lambda
> receives. This is documented in Section 11.1 of the LispWorks User
> Guide.
Hmm, I wouldn't really call that "documented," though. I haven't found
a place where it is actually specified what parameters LispWorks'
MAKE-METHOD-LAMBDA takes and in which order. I inspected
#'MAKE-METHOD-LAMBDA in the IDE and from what I saw there I came up
with this (FIXNUM declaration just inserted while experimenting):
(let ((generic-function (ensure-generic-function 'foo)))
(make-method-lambda
generic-function
(class-prototype (generic-function-method-class generic-function))
'(n &rest other-args)
'(fixnum n)
'(progn (print 'howdy)
(apply #'+ n other-args))))
Does that look right?
I think the last (BODY) parameter (except for the optional environment
argument) has to be wrapped in PROGN if it's more than one form
although LispWorks will wrap another PROGN around it anyway. Hmm...
Now to get the behaviour from my original example I tried this which
seems to work:
(let ((generic-function (ensure-generic-function 'foo)))
(add-method generic-function
(make-instance 'standard-method
:specializers (list (find-class 'integer))
:lambda-list '(n &rest other-args)
:function (compile nil (make-method-lambda
generic-function
(class-prototype
(generic-function-method-class
generic-function))
'(n &rest other-args)
nil
'(apply #'+ n other-args))))))
However, there's another question popping up:
In the MOP book (figure 5.3) they use FUNCTION instead of COMPILE
which doesn't seem to work. Do I have to use COMPILE (and thus invoke
the compiler at runtime) if I want my methods to be compiled? I had
hoped that I could create them like closures such that they are
compiled at compile time.
> At first, the separation into ADD-METHOD and MAKE-METHOD-LAMBDA
> appeared strange and unnecessary to me. However, this separation is
> necessary in order to process lexical environments correctly. In the
> most general case, you would need something like the ENCLOSE
> function defined in CLtL2 (but dropped in ANSI). LispWorks defines
> ENCLOSE - it's not documented but seems to work.
So if I don't have lexical environments to care about I can just leave
the environment parameter out, right?
> I hope this helps.
This helped a lot, thanks! I'm still not fully getting it, though. I'd
be happy if I could look at some working examples somewhere. How did
you come up with this stuff, especially the parts which are specific
to LispWorks? Did you use trial and error or am I missing something in
the docs?
Thanks again,
Edi.