Discussion:
Congruence of lamda-lists of methods with their generic-function
Jean-Claude Beaudoin
2014-02-09 04:09:31 UTC
Permalink
Hello CL Pros,

I am trying to understand the meaning in conforming ANSI CL
of the following code snippet and I am not quite sure what to think of it:

(defgeneric foo (a b &key))

(defmethod foo (a b &key c d) (or c d 42))

At this point should a call to foo accept any keyword
argument, no keyword argument or only :c and/or :d?
What would be the outcome of this:

(foo 1 2 :d 3)

Is it an error being signaled or the value 3 being returned?
I am inclined to believe that an error should be signaled,
since the generic function lambda-list contains no
explicit keyword argument and no &allow-other-keys.

Reading CLHS 7.6.4 it seems to me that
(defgeneric foo (a b &key)) and
(defgeneric foo (a b &key &allow-other-keys))
are two different things as to the set of keyword arguments
they each will accept. The first one being the empty set
and the second the set of all possible sequence of
keyword arguments (limits set aside). Am I right?

Also if I go for (defgeneric (a b &key &allow-other-keys)),
is the lambda-list of the method as here above still congruent?
Doesn't it need to be rewritten as:

(defmethod foo (a b &key c d &allow-other-keys) ...)
or
(defmethod foo (a b &rest other-args) ...)

to be properly congruent?

Thanks,

Jean-Claude Beaudoin
Didier Verna
2014-02-09 09:10:10 UTC
Permalink
Post by Jean-Claude Beaudoin
Hello CL Pros,
I am trying to understand the meaning in conforming ANSI CL
(defgeneric foo (a b &key))
(defmethod foo (a b &key c d) (or c d 42))
At this point should a call to foo accept any keyword
argument, no keyword argument or only :c and/or :d?
(foo 1 2 :d 3)
Is it an error being signaled or the value 3 being returned?
I am inclined to believe that an error should be signaled,
since the generic function lambda-list contains no
explicit keyword argument and no &allow-other-keys.
I think that's the opposite. From CLHS:

| 7.6.5 Keyword Arguments in Generic Functions and Methods
|
| When a generic function or any of its methods mentions &key in a lambda
| list, the specific set of keyword arguments accepted by the generic
| function varies according to the applicable methods. The set of keyword
| arguments accepted by the generic function for a particular call is the
| union of the keyword arguments accepted by all applicable methods and
| the keyword arguments mentioned after &key in the generic function
| definition, if any.

So because your method accepts :c and :d, then this particular call to
foo does as well. The critical thing to understand here is that the
valid keyword arguments may vary from one call to another.
--
Please help crowdfund my next Jazz quartet album !!
http://www.kisskissbankbank.com/quartet-the-second-album

Lisp, Jazz, Aïkido: http://www.didierverna.info
Pascal J. Bourguignon
2014-02-09 16:57:53 UTC
Permalink
Post by Didier Verna
Post by Jean-Claude Beaudoin
Hello CL Pros,
I am trying to understand the meaning in conforming ANSI CL
(defgeneric foo (a b &key))
(defmethod foo (a b &key c d) (or c d 42))
At this point should a call to foo accept any keyword
argument, no keyword argument or only :c and/or :d?
(foo 1 2 :d 3)
Is it an error being signaled or the value 3 being returned?
I am inclined to believe that an error should be signaled,
since the generic function lambda-list contains no
explicit keyword argument and no &allow-other-keys.
| 7.6.5 Keyword Arguments in Generic Functions and Methods
|
| When a generic function or any of its methods mentions &key in a lambda
| list, the specific set of keyword arguments accepted by the generic
| function varies according to the applicable methods. The set of keyword
| arguments accepted by the generic function for a particular call is the
| union of the keyword arguments accepted by all applicable methods and
| the keyword arguments mentioned after &key in the generic function
| definition, if any.
So because your method accepts :c and :d, then this particular call to
foo does as well. The critical thing to understand here is that the
valid keyword arguments may vary from one call to another.
Definitely.

If you want to allow any kind of keywords for any call to the generic
function, you can declare it as:

(defgeneric foo (a b &key &allow-other-keys))
(defmethod foo (a b &key c d &allow-other-keys) (or c d 42))

or alternatively, if you're concerned only with a single call, you can
call it as:

(foo unknown-object-1 unknown-object-2 :d 3 :allow-other-keys t)
--
__Pascal Bourguignon__
http://www.informatimago.com/
"Le mercure monte ? C'est le moment d'acheter !"
Pascal Costanza
2014-02-09 17:42:25 UTC
Permalink
Post by Pascal J. Bourguignon
If you want to allow any kind of keywords for any call to the generic
(defgeneric foo (a b &key &allow-other-keys))
(defmethod foo (a b &key c d &allow-other-keys) (or c d 42))
or alternatively, if you're concerned only with a single call, you can
(foo unknown-object-1 unknown-object-2 :d 3 :allow-other-keys t)
I recommend to be careful with :allow-other-keys t. I recently used it a bit too indiscriminately, and this created some problems. The reason was that I created a few levels of indirection that looked roughly like this:

(defun foo (a b c &rest args &key k1 k2)

(apply ‘bar … args)
…)

If you call (foo 1 2 3 :k3 :allow-other-keys t), this can be handy, but keep in mind that the additional keyword parameter is passed down also in &rest args, and this may screw up further processing down the lines.

It was possible to resolve this with a more careful definition of the parameter lists, and the code is now much cleaner.


Pascal

--
Pascal Costanza
The views expressed in this email are my own, and not those of my employer.
Steve Haflich
2014-02-10 04:20:42 UTC
Permalink
It is useful to understand, first, that the rules for keyword arguments
accepted by generic functions are rather different and more complex than
for non-generic functions, and second, why this is so.

A non-generic function is defined in one place, e.g. with a singe defun
form, and its keyword processing can be determined from that single form.
This remains true even if the function is redefined during run time.

A generic function is different in that it is (usually) specified by
numerous defgeneric and defmethod and defclass forms. (All of these can
add methods to a gf!) And methods can also be added and deleted
programatically at run time. The intention of the rules is that the gf
should accept a keyword arg iff there is a method willing to deal with it,
and (very important) such a keyword arg should _not_ bother any method
_not_ prepared to deal with it.

That's one reason why responsibility for keyword arg checking is placed
upon the gf, and not upon individual method functions.
Post by Didier Verna
Post by Jean-Claude Beaudoin
Hello CL Pros,
I am trying to understand the meaning in conforming ANSI CL
of the following code snippet and I am not quite sure what to think of
(defgeneric foo (a b &key))
(defmethod foo (a b &key c d) (or c d 42))
At this point should a call to foo accept any keyword
argument, no keyword argument or only :c and/or :d?
(foo 1 2 :d 3)
Is it an error being signaled or the value 3 being returned?
I am inclined to believe that an error should be signaled,
since the generic function lambda-list contains no
explicit keyword argument and no &allow-other-keys.
| 7.6.5 Keyword Arguments in Generic Functions and Methods
|
| When a generic function or any of its methods mentions &key in a lambda
| list, the specific set of keyword arguments accepted by the generic
| function varies according to the applicable methods. The set of keyword
| arguments accepted by the generic function for a particular call is the
| union of the keyword arguments accepted by all applicable methods and
| the keyword arguments mentioned after &key in the generic function
| definition, if any.
So because your method accepts :c and :d, then this particular call to
foo does as well. The critical thing to understand here is that the
valid keyword arguments may vary from one call to another.
--
Please help crowdfund my next Jazz quartet album !!
http://www.kisskissbankbank.com/quartet-the-second-album
Lisp, Jazz, Aïkido: http://www.didierverna.info
Loading...