METHOD-COMBINATION-ARGUMENTS:ARGUMENTS option to DEFINE-METHOD-COMBINATION is not specified very clearly. In particular, different generic functions using the type of method combination being defined might accept different argument patterns, so the lambda-list in the :ARGUMENTS option is unlikely to be congruent to the generic function's lambda-list; the behavior when they are not congruent should be clearly specified. Such mismatches often occur in practice, as in the example on p.6-74 where the generic function would typically have more than one argument.
88-002R says:
If lambda-list is not congruent to the generic function's lambda-list, additional ignored parameters are automatically inserted until it is congruent. Thus it is permissible for lambda-list to receive fewer arguments than the number that the generic function expects.
The current ANSI CL draft says:
If the arguments supplied to the generic function do not match lambda-list, extra arguments are ignored and missing arguments are defaulted to nil. Thus it is permissible for lambda-list to receive fewer arguments than the number of required arguments for the generic function.
This is Symbolics issue #10.
This correspondence is computed by dividing the :ARGUMENTS lambda-list
and the generic function lambda-list into three sections: the required
parameters, the optional parameters, and the keyword/rest parameters.
The arguments supplied to the generic function for a particular call
are also divided into three sections; the required arguments section
contains as many arguments as the generic function has required
parameters, the optional arguments section contains as many arguments
as the generic function has optional parameters, and the keyword/rest
arguments section contains the remaining arguments. Each parameter in
the required and optional sections of the :ARGUMENTS lambda-list
accesses the argument at the same position in the corresponding section
of the arguments. If the section of the :ARGUMENTS lambda-list is
shorter, extra arguments are ignored. If the section of the :ARGUMENTS
lambda-list is longer, excess required parameters are bound to forms
that evaluate to NIL and excess optional parameters are bound to their
initforms. The keyword/rest parameters in the :ARGUMENTS lambda-list
access the keyword/rest section of the arguments. If the :ARGUMENTS
lambda-list contains &KEY, it behaves as if it also contained
&ALLOW-OTHER-KEYS.
In addition, &WHOLE <var> can be placed first in the :ARGUMENTS
lambda-list. It causes <var> to be bound to a form that evaluates to
a list of all of the arguments supplied to the generic function. This
is different from &REST because it accesses all of the arguments, not
just the keyword/rest arguments.
;;; Example of the use of :arguments
(define-method-combination progn-with-lock ()
((methods ()))
(:arguments object)
`(unwind-protect
(progn (lock (object-lock ,object))
,@(mapcar #'(lambda (method)
`(call-method ,method))
methods))
(unlock (object-lock ,object))))
This would be used as follows:
(defgeneric send (channel buffer &optional (start 0) end)
(:method-combination progn-with-lock))
where each channel class has an object-lock method.
A variation that uses non-required arguments in :arguments is:
(define-method-combination progn-with-lock-2 ()
((methods ()))
(:arguments &key lock)
`(unwind-protect
(progn (lock ,lock)
,@(mapcar #'(lambda (method)
`(call-method ,method))
methods))
(unlock ,lock)))
This would be used as follows:
(defgeneric send (channel buffer
&optional (start 0) end
&key lock character-set-translation)
(:method-combination progn-with-lock-2))
The :lock keyword argument comes from the third section of the arguments, which for this generic function starts at the fourth argument.
To show how lambda-list mismatch works:
If (:ARGUMENTS a b c) meets DEFGENERIC (x y &optional z), the value of
the value of C will be NIL, not the value of Z.
To show the use of &WHOLE:
(define-method-combination progn-with-gf-lock ()
((methods ()))
(:arguments &whole args)
(:generic-function gf)
`(unwind-protect
(progn (lock-gf-args ,gf ,args)
,@(mapcar #'(lambda (method)
`(call-method ,method))
methods))
(unlock (unlock-gf-args ,gf ,args))))
:ARGUMENTS lambda-list while solving the congruency problems. It's likely that this is not a change from what was originally intended, but just a more precise way of describing it. The examples show why both &WHOLE and &REST are needed; using &REST in the progn-with-gf-lock example is not consistent with using &KEY in the progn-with-lock-2 example.WHOLE. In Symbolics Genera 8.0 the :ARGUMENTS option to DEFINE-METHOD-COMBINATION does not work at all (it produces incorrect code that does not compile).
TI Explorer release 6 has :ARGUMENTS in DEFINE-METHOD-COMBINATION, but its status relative to the proposed clarification is unknown at present.
Recent versions of PCL support :ARGUMENTS in DEFINE-METHOD-COMBINATION but do not seem to conform to the proposal -- I think PCL just effectively appends "&rest ignore" to the :arguments lambda-list.
I did not discover any other CLOS implementations that support :ARGUMENTS.
:ARGUMENTS more difficult.:ARGUMENTS will be specified in a way that can't be understood.:ARGUMENTS will be usable in the relatively rare circumstances where it is needed.