[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
DEFINE-METHOD-COMBINATION issues
Date: Mon, 8 May 89 22:49 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Here are some questions about unclarities in 88-002R revolving around
method combination, along with my suggested answers. Any comments?
I think I will try to use the eventual resolution of this to improve
the writeup in the ANSI Common Lisp draft specification.
Can CALL-NEXT-METHOD be called lexically within a MAKE-METHOD?
p.2-12 says CALL-NEXT-METHOD can be used in the body of a method defined
by a method-defining form, and 1-22 defines "method-defining form" and
does not include MAKE-METHOD, so I think that CALL-NEXT-METHOD is not
specified to work in MAKE-METHOD. The 2-12 text may have been meant to
exclude methods created with the chapter 3 function MAKE-METHOD-LAMBDA,
but in fact it's clear from the draft of chapter 3 that CALL-NEXT-METHOD
does work in such methods. So I don't really know what the intent of
2-12 was, but I think it would be safe to assume that CALL-NEXT-METHOD
need not be supported in MAKE-METHOD. Example:
(call-method (make-method (or (frob) (call-next-method)))
,remaining-methods)
could be rewritten:
(or (frob) (call-method ,(first remaining-methods)
,(rest remaining-methods)))
See additional discussion below.
Does CALL-METHOD use the arguments of the effective method, or does it
use the arguments of the MAKE-METHOD that it was a part of? For
example,
(DEFMETHOD CHANGE :AROUND (X &OPTIONAL (N 1))
(CALL-NEXT-METHOD X (MIN N 0)))
(DEFMETHOD CHANGE (X &OPTIONAL (N 2))
N)
What does (CHANGE T 5) return? A strict reading of the spec says 5,
but my intuition says 0, and 0 is a lot easier to implement.
If this is standard method combination, and there are no other methods,
the effective method is
(call-method <:around method>
((make-method (call-method <primary method>))))
and the target of the CALL-NEXT-METHOD is the MAKE-METHOD.
p.2-11: "The arguments are the arguments that were supplied to the
effective method form containing the invocation of CALL-METHOD."
But this is ambiguous, does "the effective method form" mean the whole
thing, or just the part containing the invocation of CALL-METHOD? If it
had meant the whole thing, I think it would have said "the arguments
that were supplied to the generic function". Also it makes more sense
that once call-next-method changes the arguments, they don't "randomly"
change back to the original arguments. So I think the example returns
0. I propose to change the text on p.2-11 to say "The arguments are the
arguments that were supplied to the innermost MAKE-METHOD-created
method enclosing the invocation of CALL-METHOD, or if there is no
MAKE-METHOD, the arguments that were supplied to the generic function."
I'd like to say this in fewer words, but couldn't think of a way.
I makes sense. I think that is the right thing to do.
Is the effective method code a real Lisp form, i.e. can it contain
forms which require closures, like:
(BLOCK TOO-DEEP
(CALL-METHOD ,(FIRST PRE-METHODS)
(,@(REST PRE-METHODS)
(MAKE-METHOD (RETURN-FROM TOO-DEEP NIL))))
(CALL-METHOD ,(FIRST POST-METHODS)
(,@(REST POST-METHODS)
(MAKE-METHOD T))))
Nothing in chapter 1 or 2 mentions any restrictions on what the
effective method form can do, so the answer should be yes. The
problem is that the description of MAKE-METHOD (p.2-11) fails to
specify the lexical environment of the form its given. Nor does
anything specify the lexical environment of the overall effective
method form. After thinking about it a bit, I believe the intention
was that both of these forms are in the null lexical environment.
Thus the answer is that this example code is not valid.
Unless there are further comments, I propose to change the ANSI
Common Lisp specification to say both effective method forms and
MAKE-METHOD forms are in the null lexical environment. Note that
this implies no CALL-NEXT-METHOD inside of MAKE-METHOD. And no
CONTINUE-WHOPPER inside of a DEFWRAPPER, to translate back to
Flavors terminology.
The only comment I have is that I don't know if it is going to be seen as a
drastic constraint or not. I'd like to see others opinion on this.
In 12/15/88 MOP Draft number 10, some places seem to think that a
METHOD-COMBINATION object consists of the information supplied to
DEFGENERIC (with a mysterious "Documentation" slot), and other places
seem to think that it consists of the information supplied to
DEFINE-METHOD-COMBINATION, but the slots only make sense for the short
form.
I agree with what was said and I don't think we need to change the document.
The issue here is that p.2-34 says "If lambda-list is not congruent to
the generic function's lambda-list, additional ignored parameters are
automatically inserted until it is congruent", but this doesn't say
where they are inserted nor what happens if inserting additional
parameters can't make it congruent (e.g. too many required parameters
to begin with). Are they inserted at the end? At the end of each
group (required, optional, keyword)? At the beginning??
We thought about simplifying this to just require the two lambda-lists
to be congruent, but that doesn't work well since a single method
combination type should be useable with many different generic functions
with different lambda-lists.
I think the best answer is to delete the stuff about congruence (the
last two sentences of the first paragraph on p.2-34) and simply say what
happens if the arguments supplied to the generic function don't match
the lambda-list: if there are too few arguments, NIL is assumed for
missing arguments. If there are too many arguments, the extra arguments
are ignored. If there are unhandled keyword arguments, they are
ignored. Supplied-p parameters work in the normal fashion. Default
value forms are evaluated in the null lexical environment (except for
bindings of :ARGUMENTS parameters to their left, of course). This is
more or less what the equivalent Flavors feature does. Any objections?
Also, what happens if the effective method form returned by your
body forms includes (setq ,variable ...) or (setf ,variable ...),
where variable is one of the :ARGUMENTS parameters? I think
the consequences should be undefined.
All of this sound good.