From: Tamas Papp
Subject: calling function with default arguments
Date: 
Message-ID: <874pkdly23.fsf@pu100877.student.princeton.edu>
I have a function that looks like 

(defun foo (dimensions &optional initial-element)
  (if initial-element
      (make-array dimensions :initial-element initial-element)
      (make-array dimensions)))

only that in my version make-array has more arguments, and repeating
them in both brances of the if statement makes a bit of repeated code.
Moreover, I have other arguments to make-array, so it would involve
multiple nested ifs.

Is there an idiom which would allow me to call another function with
its default arguments if I want to?  I am thinking of something like
this:

(make-array dimensions :initial-element (if initial-element
                                            initial-element
                                            'as-if-I-didn't-specify-this-argument))

Or if there is any other solution to my problem, I am interested in
that.

Thanks,

Tamas

From: Pascal Costanza
Subject: Re: calling function with default arguments
Date: 
Message-ID: <5fee8gF3ch69rU1@mid.individual.net>
Tamas Papp wrote:
> I have a function that looks like 
> 
> (defun foo (dimensions &optional initial-element)
>   (if initial-element
>       (make-array dimensions :initial-element initial-element)
>       (make-array dimensions)))
> 
> only that in my version make-array has more arguments, and repeating
> them in both brances of the if statement makes a bit of repeated code.
> Moreover, I have other arguments to make-array, so it would involve
> multiple nested ifs.
> 
> Is there an idiom which would allow me to call another function with
> its default arguments if I want to?  I am thinking of something like
> this:
> 
> (make-array dimensions :initial-element (if initial-element
>                                             initial-element
>                                             'as-if-I-didn't-specify-this-argument))
> 
> Or if there is any other solution to my problem, I am interested in
> that.

(defun foo (dimensions &rest args &key initial-element)
   (declare (dynamic-extent args))
   (apply #'make-array args))

or

(defun foo (dimensions &optional initial-element)
   (apply #'make-array
     `(,@(when initial-element
           (list :initial-element initial-element)))))

With the latter approach, you can nest several optional parameters in 
the backquote expression.

Beware, though, that in your approach it becomes ambiguous whether the 
user an initial element of 'nil: (foo 5 nil) yields the same result as 
(foo 5). You probably want something like this:

(defun foo
   (dimensions &optional (initial-element nil initial-element-p))
   (if initial-element-p ... ...))


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Duane Rettig
Subject: Re: calling function with default arguments
Date: 
Message-ID: <o0abu5334a.fsf@gemini.franz.com>
Pascal Costanza <··@p-cos.net> writes:

> Tamas Papp wrote:
>> I have a function that looks like (defun foo (dimensions &optional
>> initial-element)
>>   (if initial-element
>>       (make-array dimensions :initial-element initial-element)
>>       (make-array dimensions)))
>> only that in my version make-array has more arguments, and repeating
>> them in both brances of the if statement makes a bit of repeated code.
>> Moreover, I have other arguments to make-array, so it would involve
>> multiple nested ifs.
>> Is there an idiom which would allow me to call another function with
>> its default arguments if I want to?  I am thinking of something like
>> this:
>> (make-array dimensions :initial-element (if initial-element
>>                                             initial-element
>>                                             'as-if-I-didn't-specify-this-argument))
>> Or if there is any other solution to my problem, I am interested in
>> that.
>
> (defun foo (dimensions &rest args &key initial-element)
>   (declare (dynamic-extent args))
>   (apply #'make-array args))
>
> or
>
> (defun foo (dimensions &optional initial-element)
>   (apply #'make-array
>     `(,@(when initial-element
>           (list :initial-element initial-element)))))

Both of these apply-solutions will work, of course.  However, if the
lisp does any optimizations on make-array, they might not be
performed with apply in the mix, because the decision to include or
exclude the keyword is being made at run time.

Macros are our friends, as usual.  Here is a sketch, untested, but
which should provide a basis for a make-array call with an explicit
compile-time initial-element value (but nil as an initial-element is
not an option; for that the macro would have to be slightly more
complex).  The nice thing about making the decision at macroexpand
time is that the compiler can then get in on the action...

(macrolet ((do-make-array (dim i-e &rest keys
	     (let ((new-keys (if i-e
				 (append `(:initial-element ,i-e) keys)
			       (remf (copy-list keys) :initial-element))))
	       `(make-array ,dim ,@keys)))))
  
  ...
  (if specify-the-initial-element
      (do-make-array dimensions initial-element ...)
    (do-make-array dimensions nil ...)))

Of course, defmacro could be used, and on user-defined functions that
accept keywords define-compiler-macro could also be used directly to
go through the same pre-decision process.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Alan Crowe
Subject: Re: calling function with default arguments
Date: 
Message-ID: <86zm25zr03.fsf@cawtech.freeserve.co.uk>
Tamas Papp <······@gmail.com> writes:

> I have a function that looks like 
> 
> (defun foo (dimensions &optional initial-element)
>   (if initial-element
>       (make-array dimensions :initial-element initial-element)
>       (make-array dimensions)))
> 
> only that in my version make-array has more arguments, and repeating
> them in both brances of the if statement makes a bit of repeated code.
> Moreover, I have other arguments to make-array, so it would involve
> multiple nested ifs.
> 

I wonder if this code is doing what you think it is
doing. Common Lisp distinguishes between providing an
optional initial-element that is explicitly specified to be
NIL and not providing one at all. It works like this:

First you can include a form to be evaluated to supply a
default value if the optional argument is omitted.

(defun maybe (&optional (arg 'default)) arg)

(maybe) => DEFAULT
(maybe nil) => NIL
(maybe 'given) => GIVEN

(defun maybe (&optional arg) ...) is the same as
(defun maybe (&optional (arg nil)) ...)

So your code uses the default value of nil as code for
"omitted" which makes it impossible to specify an
initial-element of NIL even by explicitly requesting it.

Second you can include a flag variable that Common Lisp will
set to indicate that the optional value was actually
supplied.

CL-USER> (defun perhaps (&optional 
                         (first 'this first-supplied)
                         (second 'that second-supplied))
           (format t "~&first=~A, second=~A, flags mean ~A"
                   first
                   second
                   (cond (second-supplied "both-supplied")
                         (first-supplied "only the first supplied")
                         (t "neither supplied"))))
PERHAPS

CL-USER> (dolist (arglist '((1 2)
                            (1)
                            ()))
           (apply #'perhaps arglist))

first=1, second=2, flags mean both-supplied
first=1, second=THAT, flags mean only the first supplied
first=THIS, second=THAT, flags mean neither supplied

Alan Crowe
Edinburgh
Scotland
From: Duane Rettig
Subject: Re: calling function with default arguments
Date: 
Message-ID: <o0644t327j.fsf@gemini.franz.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> Tamas Papp <······@gmail.com> writes:
>
>> I have a function that looks like 
>> 
>> (defun foo (dimensions &optional initial-element)
>>   (if initial-element
>>       (make-array dimensions :initial-element initial-element)
>>       (make-array dimensions)))
>> 
>> only that in my version make-array has more arguments, and repeating
>> them in both brances of the if statement makes a bit of repeated code.
>> Moreover, I have other arguments to make-array, so it would involve
>> multiple nested ifs.
>> 
>
> I wonder if this code is doing what you think it is
> doing. Common Lisp distinguishes between providing an
> optional initial-element that is explicitly specified to be
> NIL and not providing one at all. It works like this:

I think the OP understands the issue.  It is a statement of the
problem in Common Lisp that there is no direct way to specify that a
keyword is unspecified (i.e. that the default value should be used for
the particular keyword).

Imagine in a parallel universe a Common Lisp that allowed a special
value to be passed as the value of a keyword, say that value is
something like :use-default.  When the keyword processing for the
receiving function sees that special value, it treats the keyword as
if the keyword had not been passed at all, and thus uses the default
that is specified for the keyword.

One might argue that such a special word clutters the space for
possible values for keywords, and that would be correct; no keyword
could ever have the value :use-default as a non-default value.
However, it would not be a very strong argument; there is precedent
set in the names of keywords themselves; there is a special keyword
named :allow-other-keys, which can never be the name of a real
keyword...

The legitimate arguments against such a special keyword value that I
can think of are:

 1. There are at least two workarounds, using macros or apply.

 2. The processing of keywords would become yet more cumbersome, with
higher overhead to test for the special value.  (this same argument
could be made against :allow-other-keys, but a-o-k has no good
workaround so the overhead seems acceptable)

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Barry Margolin
Subject: Re: calling function with default arguments
Date: 
Message-ID: <barmar-000836.21024409072007@comcast.dca.giganews.com>
In article <··············@gemini.franz.com>,
 Duane Rettig <·····@franz.com> wrote:

> Alan Crowe <····@cawtech.freeserve.co.uk> writes:
> 
> > Tamas Papp <······@gmail.com> writes:
> >
> >> I have a function that looks like 
> >> 
> >> (defun foo (dimensions &optional initial-element)
> >>   (if initial-element
> >>       (make-array dimensions :initial-element initial-element)
> >>       (make-array dimensions)))
> >> 
> >> only that in my version make-array has more arguments, and repeating
> >> them in both brances of the if statement makes a bit of repeated code.
> >> Moreover, I have other arguments to make-array, so it would involve
> >> multiple nested ifs.
> >> 
> >
> > I wonder if this code is doing what you think it is
> > doing. Common Lisp distinguishes between providing an
> > optional initial-element that is explicitly specified to be
> > NIL and not providing one at all. It works like this:
> 
> I think the OP understands the issue.  It is a statement of the
> problem in Common Lisp that there is no direct way to specify that a
> keyword is unspecified (i.e. that the default value should be used for
> the particular keyword).

I think Alan understands that.  I think his point was that if you do

(foo '(3 4) nil)

it will not use the initial element that you specified explicitly.  This 
is why the code should use a supplied-p parameter, and conditionalize on 
that.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Kent M Pitman
Subject: Re: calling function with default arguments
Date: 
Message-ID: <u644t805q.fsf@nhplace.com>
Duane Rettig <·····@franz.com> writes:

> I think the OP understands the issue.  It is a statement of the
> problem in Common Lisp that there is no direct way to specify that a
> keyword is unspecified (i.e. that the default value should be used for
> the particular keyword).

Well, there is a way.  It's not straightforward, but it does not require
using more than one call and it does not require apply, which is what I
take as the technical definition of the problem.  I'll give you another
chance before I spoil the fun by offering an answer.
From: Pascal Costanza
Subject: Re: calling function with default arguments
Date: 
Message-ID: <5fgpseF3ch2hkU1@mid.individual.net>
Kent M Pitman wrote:
> Duane Rettig <·····@franz.com> writes:
> 
>> I think the OP understands the issue.  It is a statement of the
>> problem in Common Lisp that there is no direct way to specify that a
>> keyword is unspecified (i.e. that the default value should be used for
>> the particular keyword).
> 
> Well, there is a way.  It's not straightforward, but it does not require
> using more than one call and it does not require apply, which is what I
> take as the technical definition of the problem.  I'll give you another
> chance before I spoil the fun by offering an answer.

(defvar *unspecified* (list 'unspecified))

(defun foo (&optional (arg *unspecified*))
   (if (eq arg *unspecified*) ... ...))


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Tamas Papp
Subject: Re: calling function with default arguments
Date: 
Message-ID: <87644sk8x2.fsf@pu100877.student.princeton.edu>
Pascal Costanza <··@p-cos.net> writes:

> Kent M Pitman wrote:
>> Duane Rettig <·····@franz.com> writes:
>>
>>> I think the OP understands the issue.  It is a statement of the
>>> problem in Common Lisp that there is no direct way to specify that a
>>> keyword is unspecified (i.e. that the default value should be used for
>>> the particular keyword).
>>
>> Well, there is a way.  It's not straightforward, but it does not require
>> using more than one call and it does not require apply, which is what I
>> take as the technical definition of the problem.  I'll give you another
>> chance before I spoil the fun by offering an answer.

Unless its with macros (like Duane's code), I don't see it, so please
tell us the answer.

> (defvar *unspecified* (list 'unspecified))
>
> (defun foo (&optional (arg *unspecified*))
>   (if (eq arg *unspecified*) ... ...))

I don't get to define the function: I want to call library functions
and functions defined by others too.

Tamas
From: Madhu
Subject: Re: calling function with default arguments
Date: 
Message-ID: <m3bqekxruc.fsf@robolove.meer.net>
[cancelled and reposted; fixing a bug]

* Tamas Papp <··············@pu100877.student.princeton.edu> :
| Pascal Costanza <··@p-cos.net> writes:
|> Kent M Pitman wrote:
|>> Duane Rettig <·····@franz.com> writes:
|>>
|>>> I think the OP understands the issue.  It is a statement of the
|>>> problem in Common Lisp that there is no direct way to specify that a
|>>> keyword is unspecified (i.e. that the default value should be used for
|>>> the particular keyword).
|>>
|>> Well, there is a way.  It's not straightforward, but it does not require
|>> using more than one call and it does not require apply, which is what I
|>> take as the technical definition of the problem.  I'll give you another
|>> chance before I spoil the fun by offering an answer.
|
| Unless its with macros (like Duane's code), I don't see it, so please
| tell us the answer.

I don't see it either -- if the requirement I see is that the call has
to omit that keyword (+ argument) to get the default behaviour.

[At best I can see some of the keyword processing moved closer to the
call site using the macro's environment, but dont see a win there.]

Maybe he can give a spoiler :)


But going with macros, here is my solution of a generalized call frobber
that removes keywords with :use-default values from a call.

[Unlike :allow-other-keys] The parsing suffers from the defect that
Duanne anticipated, that :use-default is special and cannot appear as a
key or a regular argument to the call.

Other style warnings or why this is a bad idea? [I know it is but can't
articulate why :)]

(defun frob-use-default-keys (args)
  "Remove key-value pairs that have value :USE-DEFAULT from the property
list which is a tail of the list ARGS. The value :USE-DEFAULT should
occur only as values in the property list."
  (loop with x = args and p and q while x 
        if (eq (cadr x) :use-default) do
        (cond ((null q)
               (cond ((null p)
                      (setq args (cddr args)))
                     (t (setf (cdr p) (cddr x))
                        (setq q p))))
              (t (setf (cdr q) (cddr x))))
        (setq x (cddr x))
        else do
        (cond ((null q) (setq p x x (cdr x)))
              (t (setq q (cdr x) x (cddr x)))))
  args)

(defmacro frob ((func &rest call-args))
  `(,func ,@(frob-use-default-keys call-args)))

(macroexpand-1 '(frob (make-array '(10 20)
                       :initial-element 100
                       :element-type :use-default)))

|> (defvar *unspecified* (list 'unspecified))
|>
|> (defun foo (&optional (arg *unspecified*))
|>   (if (eq arg *unspecified*) ... ...))
|
| I don't get to define the function: I want to call library functions
| and functions defined by others too.

--
Madhu
From: Kent M Pitman
Subject: Re: calling function with default arguments
Date: 
Message-ID: <u1wfh7zn2.fsf@nhplace.com>
Duane Rettig <·····@franz.com> writes:

> ... there is a special keyword named :allow-other-keys, which 
> can never be the name of a real keyword...

As far as I know, it's not reserved.

I looked it up after my error today with doc strings. Sigh.
From the end of 3.4.1.4 Specifiers for keyword parameters:

  Furthermore, if the receiving argument list specifies a regular
  argument which would be flagged by :allow-other-keys, then
  :allow-other-keys has both its special-cased meaning (identifying
  whether additional keywords are permitted) and its normal meaning
  (data flow into the function in question).


That is, it just has pre-defined meaning in addition to its use that
any user might do:

  ((lambda (&key allow-other-keys) allow-other-keys)
   :allow-other-keys 3)
  => 3

  It's certainly true that:

  ((lambda (&key allow-other-keys) allow-other-keys)
   :allow-other-keys 3
   :foo t)
  => 3

rather than an error [as long as the value isn't nil, I mean--heh].
But that's not strictly the same as saying it's not a real keyword.

Lest you think this is inconsistent with the rest of the language,
consider the following case, which seems analogous and I bet you
wouldn't think twice about doing:

  (defclass foo ()
    ((x :initarg :x :accessor foo-x)
     (y :accessor foo-y)))
  #<STANDARD-CLASS FOO 2067E4BC>

  (defmethod initialize-instance :after ((foo foo) &key x)
    (setf (foo-y foo) x))
  #<STANDARD-METHOD INITIALIZE-INSTANCE (:AFTER) (FOO) 2069A0D4>

  (foo-y (make-instance 'foo :x 3))
  3

but yet no one says that :x isn't a "real" init arg.  It's just used in
multiple ways.
From: Duane Rettig
Subject: Re: calling function with default arguments
Date: 
Message-ID: <o0lkdn6egn.fsf@gemini.franz.com>
Kent M Pitman <······@nhplace.com> writes:

> Duane Rettig <·····@franz.com> writes:
>
>> ... there is a special keyword named :allow-other-keys, which 
>> can never be the name of a real keyword...
>
> As far as I know, it's not reserved.

Well, I didn't actually say that it was a reserved word, but perhaps I
used the word "real" in a pejorative sense that I shouldn't have done.

> I looked it up after my error today with doc strings. Sigh.
> From the end of 3.4.1.4 Specifiers for keyword parameters:
>
>   Furthermore, if the receiving argument list specifies a regular
>   argument which would be flagged by :allow-other-keys, then
>   :allow-other-keys has both its special-cased meaning (identifying
>   whether additional keywords are permitted) and its normal meaning
>   (data flow into the function in question).
>
>
> That is, it just has pre-defined meaning in addition to its use that
> any user might do:
>
>   ((lambda (&key allow-other-keys) allow-other-keys)
>    :allow-other-keys 3)
>   => 3
>
>   It's certainly true that:
>
>   ((lambda (&key allow-other-keys) allow-other-keys)
>    :allow-other-keys 3
>    :foo t)
>   => 3
>
> rather than an error [as long as the value isn't nil, I mean--heh].
> But that's not strictly the same as saying it's not a real keyword.

Correct - I withdraw the snub.  Instead, I'll lighten it up by saying
that it is a keyword with restrictions and possible surprises, as your
example so aptly demonstrates.  My point is that whenever a special
case is made in a namespace or semantic space, that space is limited
ever so slightly, and that to me is not the best of designs.  The fact
that you had to look it up (and I didn't realize that it was not as
limiting as I had thought) is an indicator that the design is at least
not fully intuitive.

> Lest you think this is inconsistent with the rest of the language,
> consider the following case, which seems analogous and I bet you
> wouldn't think twice about doing:
>
>   (defclass foo ()
>     ((x :initarg :x :accessor foo-x)
>      (y :accessor foo-y)))
>   #<STANDARD-CLASS FOO 2067E4BC>
>
>   (defmethod initialize-instance :after ((foo foo) &key x)
>     (setf (foo-y foo) x))
>   #<STANDARD-METHOD INITIALIZE-INSTANCE (:AFTER) (FOO) 2069A0D4>
>
>   (foo-y (make-instance 'foo :x 3))
>   3
>
> but yet no one says that :x isn't a "real" init arg.  It's just used in
> multiple ways.

I guess I don't see the analogy; perhaps it is in the misunderstanding
I caused by my use of the word "real" in my snub of allow-other-keys -
I'm really talking about limiting a semantic space by carving out a
piece of it for "special" use.  As I see it here, you're performing a
data flow operation, (and yes, I would think twice about doing it :-)
[on second thought, there might be such an application for
backward-compatibility in an api... (there, I thought twice about it :-) ] 

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Kent M Pitman
Subject: Re: calling function with default arguments
Date: 
Message-ID: <uvecrkd0c.fsf@nhplace.com>
Duane Rettig <·····@franz.com> writes:

> Correct - I withdraw the snub.

Heh.  

> Instead, I'll lighten it up by saying that it is a keyword with
> restrictions and possible surprises,

Well, all things that one doesn't know about are potential surprises, so
yes, in the sense that it's in a syntactic space that one migth model as
empty, that's an issue.  But another way to look at it is that it's like
PI in the variable space or CAR in the functional space where people will
run into it because they're not reading the spec.  I guess it's slightly
worse than that because keywords rather than packaged symbols ared used
for keyword args (if you don't go out of your way to insist on your own
packaged symbols as keys--which is syntactically painful), so collisions 
are slightly more easily going to happen, at least in theory ... The other
thing is that in keyword arguments, the total number of keywords ever needed
is tiny, so the chances of encountering this one keyword  by accident 
is vanishingly small--but that's probably an unfair argument.
 
> as your example so aptly demonstrates.  My point is that whenever a
> special case is made in a namespace or semantic space, that space is
> limited ever so slightly, and that to me is not the best of designs.
> The fact that you had to look it up (and I didn't realize that it
> was not as limiting as I had thought) is an indicator that the
> design is at least not fully intuitive.

Or it's an indication that it's not a problem even though the theory
predicts it. :)

> > Lest you think this is inconsistent with the rest of the language,
> > consider the following case, which seems analogous and I bet you
> > wouldn't think twice about doing:
> >
> >   (defclass foo ()
> >     ((x :initarg :x :accessor foo-x)
> >      (y :accessor foo-y)))
> >   #<STANDARD-CLASS FOO 2067E4BC>
> >
> >   (defmethod initialize-instance :after ((foo foo) &key x)
> >     (setf (foo-y foo) x))
> >   #<STANDARD-METHOD INITIALIZE-INSTANCE (:AFTER) (FOO) 2069A0D4>
> >
> >   (foo-y (make-instance 'foo :x 3))
> >   3
> >
> > but yet no one says that :x isn't a "real" init arg.  It's just used in
> > multiple ways.
> 
> I guess I don't see the analogy; perhaps it is in the misunderstanding
> I caused by my use of the word "real" in my snub of allow-other-keys -
 
Well, to the analogy, in both cases there is a data flow path that already
has a meaning at one point in the program [let's say that the initarg for
they x in the defclass is already taken] and I want to extend the same data
flow [rather than pick a new one--I could just as well have said &key y in
the initialize-instance, but I chose to voluntarily piggy-back on data flow
already happening.  In the FOO class example, there would be no issue at all
with the &key y, as there would be no issue with &key allow-other-keys if I
used another &key allow-different-keys to pass my questionable piece of data.
In both cases, it would change the caller's life, but it would simplify the
explanation.  And in both cases, if you didn't know half the protocol, you
might surprise yourself if you stumbled into it without reading up on the
current state before extending things yourself.

> I'm really talking about limiting a semantic space by carving out a
> piece of it for "special" use.

Certainly a thing to be avoided if one can help it.  I hope this point
doesn't get lost amid the other stuff.

>  As I see it here, you're performing a
> data flow operation, (and yes, I would think twice about doing it :-)
> [on second thought, there might be such an application for
> backward-compatibility in an api... (there, I thought twice about it :-) ] 

It's all about making sure that if you do this, people know, so they
don't accidentally stumble into it.  

And "NIL" is a much more compelling one to talk about if one is going
to talk about holes in the middle of a namespace.  ;)

- - - 

No one has taken me up on my challenge, so I'll offer an alternative just
to lighten up the mood, and to reward anyone who slugged through the above
minutiae with a bit of fun...

The following requires no call to APPLY and no faking up of the underlying
default...

 (defun secret-or-hard-to-compute-default (n)
   (* n 17))

 (defun foo-1 (&key (bar (secret-or-hard-to-compute-default 5))
                    (baz (secret-or-hard-to-compute-default 13)))
   (* bar baz))

 (defun foo-2 (&key (bar nil bar-p) (baz nil baz-p))
   (foo-1 (if bar-p :bar :no-bar)
          (if bar-p  bar :unused)
          (if baz-p :baz :no-baz)
          (if baz-p  baz :unused)
          :allow-other-keys t))

Actually, I suppose if you wanted to REALLY confuse people, you could use 

 (defun foo-2 (&key (bar nil bar-p) (baz nil baz-p))
   (foo-1 (if bar-p :bar :allow-other-keys)
          (if bar-p  bar :unused)
          (if baz-p :baz :allow-other-keys)
          (if baz-p  baz :unused)))

Note: In this last case, allow-other-keys is not being used in this 
  last case for its normal meaning at all [to change whether other 
  keys are allowed], nor is it used to carry data flow [exactly], 
  but rather it's used for its property of having a "can pass through
  freely" badge at the border.  This allows for situtations where
  there are multiple uses of it with conflicting associated values,
  as in:
  ((lambda (&key) 3) :allow-other-keys nil :allow-other-keys t) => 3
  But so it goes.  It's not like it's named :allow-this-or-other-keys,
  after all.
From: Rob Warnock
Subject: Re: calling function with default arguments
Date: 
Message-ID: <QsOdnbhKPLP9JwnbnZ2dnUVZ_s3inZ2d@speakeasy.net>
Kent M Pitman  <······@nhplace.com> wrote:
+---------------
| No one has taken me up on my challenge, so I'll offer an alternative just
| to lighten up the mood, and to reward anyone who slugged through the above
| minutiae with a bit of fun...
...
|  (defun foo-2 (&key (bar nil bar-p) (baz nil baz-p))
|    (foo-1 (if bar-p :bar :no-bar)
|           (if bar-p  bar :unused)
|           (if baz-p :baz :no-baz)
|           (if baz-p  baz :unused)
|           :allow-other-keys t))
+---------------

Oooh! That's just *evil*! I love it!!

+---------------
| Actually, I suppose if you wanted to REALLY confuse people, you could use 
| 
|  (defun foo-2 (&key (bar nil bar-p) (baz nil baz-p))
|    (foo-1 (if bar-p :bar :allow-other-keys)
|           (if bar-p  bar :unused)
|           (if baz-p :baz :allow-other-keys)
|           (if baz-p  baz :unused)))
+---------------

Even more so!  ;-}  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607