[comp.lang.lisp] optional and key arguments

bds@mbunix.mitre.org (Barry D Smith) (08/23/89)

Since we were just burnt by this on a Symbolics, I wonder 
if anyone would comment:

Given the function:

(defun test (a b &optional (c 0) &key (d 1))
  (if (= d 1)
      (+ a b c d)
      (+ a b c)))

(test 5 4 :d 0) results in an error.  

Since optional arguments are evaluated first, c is bound to :d, and 0
isn't a key argument.  Is this the Common Lisp standard?  If so, does
it make sense?  In our case, we had 3 optional arguments, and we
wanted to use the default values, but to set the key argument to
something else.  It seems a violation of the notion of optional
arguments to have to specify them.

Barry Smith

shiffman%basselope@Sun.COM (Hank Shiffman) (08/27/89)

In article <64922@linus.UUCP> bds@mbunix (Smith) writes:
>Since we were just burnt by this on a Symbolics, I wonder 
>if anyone would comment:
>
>Given the function:
>
>(defun test (a b &optional (c 0) &key (d 1))...
>
>(test 5 4 :d 0) results in an error.  
>

Yep.  This is just the way things are supposed to work.  If you have
both optional and keyword arguments, you must provide *all* the
optional arguments to get access to any of the optional ones.


-- 
Hank Shiffman                                     (415) 336-4658
Marketing Technical Specialist
Software Engineering Technologies               ...!sun!shiffman
Sun Microsystems, Inc.                          shiffman@Sun.com

barmar@think.COM (Barry Margolin) (08/28/89)

In article <64922@linus.UUCP> bds@mbunix (Smith) writes:
>(defun test (a b &optional (c 0) &key (d 1))
>(test 5 4 :d 0) results in an error.  
>Is this the Common Lisp standard?

Yes.  See p.61 of CLtL.  Optional arguments are processed before
keyword arguments.

>  If so, does it make sense?  

Yes.  How would you propose that Lisp determine whether the :D is
supposed to be an argument name or the value of the C argument?  In
the above case *you* can tell that it was intended as an argument name
because you gave an incorrect number of arguments, but that isn't always
possible.  Consider:

	(defun test (&optional a b &key d) ...)
	(test :d :e)

This binds A to :D, B to :E, and D to NIL and gets no error.  How
would a Lisp system determine that you actually meant to set the D
argument?

Don't try to special case arguments that are symbols in the KEYWORD
package.  First of all, that would break lots of things; many
functions that keyword-valued arguments.  Second, argument names don't
even have to be in the KEYWORD package; consider:

	(defun test (&optional a b &key ((c-name c) nil)) ...)
	(test 'c-name 'c-val)

This binds A to C-NAME, B to C-VAL, and C to NIL.  Lisp can't tell
that you meant it to be interpreted as

	(test nil nil 'c-name 'c-val)

>In our case, we had 3 optional arguments, and we
>wanted to use the default values, but to set the key argument to
>something else.  

This is why it's generally a bad idea to have both optional and
keyword arguments in the same function.  You should turn them all into
keyword arguments.

>It seems a violation of the notion of optional
>arguments to have to specify them.

Well, you have to specify the Nth optional argument if you want to
specify the N+1th one.  Named arguments can be thought of as a single,
last optional argument which is automatically parsed.  Or they can be
considered as automatically-parsed &REST arguments.  Either of these
analogies will help you remember that optional arguments must be
specified first.

Lisp isn't Ada.

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

jeff@aiai.uucp (Jeff Dalton) (08/28/89)

In article <64922@linus.UUCP> bds@mbunix (Smith) writes:
>(defun test (a b &optional (c 0) &key (d 1))
>  (if (= d 1)
>      (+ a b c d)
>      (+ a b c)))

>(test 5 4 :d 0) results in an error.  

>Since optional arguments are evaluated first, c is bound to :d, and 0
>isn't a key argument.  Is this the Common Lisp standard?  If so, does
>it make sense?  In our case, we had 3 optional arguments, and we
>wanted to use the default values, but to set the key argument to
>something else.  It seems a violation of the notion of optional
>arguments to have to specify them.

This behavior is correct Common Lisp.  To specify any arguments that
occur after the optional ones, you have to specify the optional
arguments.  The reason it may look strange in this case is that you
seem to be supposing that use of a keyword in a function call should
automatically indicate a keyword parameter.  However, keywords are
just a kind of symbol and are used for a number of different purposes.
For example, in (LIST :A :B) => (:A :B), both :A and :B are used
just as data objects, and neither indicates that a keyword parameter
should follow.

If you never want to use keywords except to indicate keyword
parameters, you may well think that Common Lisp has made a mistake.
But many programmers do use keywords for other purposes.  For example,
in some object systems, keywords are used a method names, as in

   (send aWindow :redisplay)

-- Jeff

miller@CS.ROCHESTER.EDU (Brad Miller) (08/29/89)

    Since optional arguments are evaluated first, c is bound to :d, and 0
    isn't a key argument.  Is this the Common Lisp standard?  

Yes; for a detailed description, read page 61 of CLtL, and the copious
examples on pgs. 63-65.

    If so, does
    it make sense?  

How else could you do it? (for generality, remember to handle the case of
two optional args, the first of which expects an argument of type keyword)
If you *really* want the effect of both, try not specifying either optional
or keyword args, but &rest only, and then process it yourself according to
any arcane rules you like... or write your own version of Defun (Defunny?)
that handles the lambda list for you by your own rules... and having a
sample implementation is 50% of getting something into the standard. Are we
having fun yet? :-)