[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>
    To: Common-Lisp@SU-AI.ARPA
    Subject: (DELETE ... :COUNT NIL)
    Message-ID: <860313155229.1.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM>
    
    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 ...
    
    and not
    
     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))
    
    and
    
	    (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.
See above.    
    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
       being defined.
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
       such.
The manual should always clearly state what the default for a keyword is.    

	-- Nick