[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: (DELETE ... :COUNT NIL)
Date: Thu, 13 Mar 86 15:52 EST
From: Kent M Pitman <KMP@SCRC-STONY-BROOK.ARPA>
Subject: (DELETE ... :COUNT NIL)
I cannot find any place in CLtL where it specifies what will happen if you
try to do:
(DELETE thing list :COUNT NIL)
Cf. pg 247, first para.
The discussion of keywords on p62 suggests that keywords get initialized to
NIL if not supplied.
I assume you mean "if [an initform is] not supplied."
On p254, the notation used to describe DELETE is ambiguous. Because the
syntax is described as
DELETE @i(item) @i(sequence) &key :from-end :test ...
DELETE @i(item) @i(sequence) &key from-end test ...
it's hard to tell whether the author meant to imply that these keywords would
default to NIL if unsupplied or whether there might be initial values that
he wasn't telling us about.
I don't understand why the colon-prefix makes a difference. The
default value for :from-end is nil (cf. pg 246). The default value for
:test is EQL (or maybe #'EQL, cf. pg 245).
From experience, I have learned to distrust the initializations of &optional
and &key variables because they frequently lead to confusion. That is, if you
tell someone "the stream is optional and defaults to standard output", they
still can't tell without constructing an experiment whether you mean:
(DEFUN FOO (&OPTIONAL STREAM ...)
(IF (NOT STREAM) (SETQ STREAM *STANDARD-OUTPUT*))
or (DEFUN FOO (&OPTIONAL (STREAM *STANDARD-OUTPUT*) ...)
The latter may seem to be implied, but in my experience, the former
implementation is much more robust since it allows one to simply write
NIL when they only want to specify a later variable. eg, if I only want
to supply a second argument of 3, I can write:
(FOO NIL 3)
to match the first implementation, but must write:
(FOO *STANDARD-OUTPUT* 3)
if the implementation is the second. In cases where the default is computed
in some hairy and/or private way, the situation complicates considerably.
The right thing to do is to say "if the STREAM is unsupplied or NIL it
defaults to the value of the special variable *standard-input*" (cf.
pg 374). This can be implemented with
(defun foo (&optional (stream nil))
(setf stream (or stream *standard-output*))...)
Sometimes, the actual implementation may even have been driven by irrelevant
issues like whether the arglist was `getting too cluttered' and the writer
may have just taken the initialization down in the body to `pretty
things up' without really thinking out what the semantic effect of that
change would be.
The argument for &KEY is similar. It may turn out that you want to define
a function DELQ as per Maclisp. Two possible implementations present themselves:
(DEFUN DELQ (THING LIST &OPTIONAL COUNT)
(DELETE THING LIST :TEST #'EQ :COUNT COUNT))
(DEFUN DELQ (THING LIST &OPTIONAL (COUNT NIL COUNT-P))
(APPLY #'DELETE THING LIST :TEST #'EQ (IF COUNT-P (LIST :COUNT COUNT) '())))
Is this perspicuous enough?
(defun delq (thing list &optional (count nil))
(delete thing list :test #'eq :count (or count (length list))))
Personally, I think the former is more perspicuous, but it can only be written
if we define that it is acceptable for DELETE to take a :COUNT argument of NIL.
If the definition of DELETE is left as vague as it is now, only the second
implementation of DELQ above will be portable.
This issue is obviously more general than just DELETE.
My conclusions from all this are as follows:
* The manual is simply ambiguous on this point currently and unless someone can
cite a definitive passage, I guess we'll have to resign ourselves to this not
See above passage.
* Wherever it is possible to get some concensus, I think we should strive to
make passing a keyword of NIL be the same as not passing a keyword. There
will be cases where this will not be possible, so I am not suggesting that
this be an across the board thing -- but I think it can usefully be handled
on a case-by-case basis. :COUNT, :TEST, and :TEST-NOT keywords are good places
to start, however, since there could be no confusion about whether the NIL
was intended as a valid argument. Things like :VERBOSE would not be candidates
since NIL is already valid as an explicit argument.
I think this is the current consensus. I think that all keywords for
which NIL is an invalid argument are documented as "if supplied and
not NIL" (i.e., supplying NIL is equiv. to not supplying the keyword
arg). Two exceptions are :test and :test-not. This should be
clarified on page 246.
* Where there is no concensus, or where we agree that passing a keyworded value
of NIL is different than passing no argument, the manual should clearly indicate
The manual should always clearly state what the default for a keyword is.