From: Kent M Pitman
Subject: Re: please help: options processing
Date: 
Message-ID: <sfwr9w4wal0.fsf@world.std.com>
Sam Steingold <ยทยทยท@goems.com> writes:

It would be easier if this were using keyworded calls. 
You have foo, bar, and baz using with-zzz options that
are not keyworded, but I'm going to make them keyworded
in my rewrites.  I'll leave it to you to reconcile that mess.
 
> Right now I have the following (I omit `unwind-protect', `let' etc):
> 
> (defmacro with-zzz ((&rest options) &body body)
>   `(progn (zzz-options ,@options) ,@body))
 
(defmacro with-zzz* ((&rest options*) &body body)
  `(progn (apply #'zzz-options options*) ,@body))

> (defun zzz-options (opt0 opt1 opt2 ...  opt10)
>   "called only from `with-zzz'"
>   ...)
> 
> (defun foo (arg0 arg1 &keys (opt0 foo-default) opt1 opt2 ... opt10)
>    [possibly modify opt0...5, but never opt6...10]
>    (with-zzz (opt0 opt1 opt2 ... opt10)
>       ....))
 
(defun foo (arg0 arg1 &rest opts
		      &keys (opt0 foo-default) opt1 opt2 ... opt5
		      &allow-other-keys)
  [possibly modify opt0...5]
  (with-zzz* (:opt0 opt0 :opt1 opt1 :opt2 opt2
	      :opt3 opt3 :opt4 opt4 :opt5 opt5
              opts) ;don't worry about removing shadowed options
    ...))

> (defun bar (arg0 arg1 &keys (opt0 bar-default) opt1 opt2 ... opt10)
>    [possibly modify opt0...5, but never opt6...10]
>    (with-zzz (opt0 opt1 opt2 ... opt10)
>       ....))

as for foo.
 
> (defun baz (arg0 arg1 &keys (opt0 baz-default) opt1 opt2 ... opt10)
>    [possibly modify opt0...5, but never opt6...10]
>    (with-zzz (opt0 opt1 opt2 ... opt10)
>       ....))

again.
 
> what I don't like is that whenever I want to add a new option, I have to
> modify `zzz-options' as well as `foo', `bar' and `baz'.  I know of
> &allow-other-keys (and I use it in other places).
> Any suggestions?

&allow-other-keys is what i'd use, as illustated above.
you have to pick up the other keys with &rest.
and you have  to take into account that if you do
 (apply #'something :foo 3 '(:foo 4 :bar 5))
that this will reliably override the :foo 4 with a :foo value of 3.
as a result, you can always just pass along the full list of keys
overriding the ones you want by making them earlier args to apply.

if you use the strategy i've outlined above, you only have to modify the
functions which want to override the newly added keyword, which is as it
should be.

good luck.
 --Kent