[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


The Problem:
 CLtL is overly vague about legal values for the :COUNT keyword.  It says
that the keyword specifies "how many occurrences of the item should be
affected" (e.g., for REMOVE, it's the maximum number of items to remove).
If the value is NIL, it means "all occurrences".  CLtL doesn't say
explicitly that the value of :COUNT must be an integer, nor does it say
what to do for negative values.

Current Practice:
 CMU Common Lisp and KCL behave differently when given a negative fixnum
for the :COUNT keyword.  CMU Common Lisp treats any value other than a
non-negative fixnum (e.g., values like -2, or 1.0) as if it were NIL.  KCL
treats negative fixnums as equivalent to zero for lists, but does something
bizarre for vectors (it pads them with n blanks or NILs, where -n is the
value of the :count keyword keyword.)

  Add language to CLtL specifying that the only legal values for :COUNT
are integers and NIL.

 Restricting :COUNT to integers most likely reflects CLtL's original
intent.  Similar functions that accept numeric args, like NTH, explicitly
limit them to integers (CLtL, p. 265).  The proposal simply makes this
explicit for the :COUNT keyword.

  Require functions that accept a :COUNT keyword to treat negative values
as equivalent to zero.

 The proposed treatment of negative values is consistent with the current
wording of CLtL, which says (p. 253, for REMOVE) "if more than :count
elements satisfy the test, then of these elements only the leftmost are
removed, as many as specified by :count."  Of course, you can't remove -3
items from a sequence, but for that matter you can't remove 3 items from a
sequence of length 2, either.  It is implicitly understood that "as many
as" really means "no more than" as far as :COUNT is concerned.

 The proposal also has the advantage of freeing the user from having to do
an explicit check for negative numbers when the value of :COUNT is computed
by some complex expression.  Example:

  (defun leave-at-most (n item sequence &key (from-end t))
    (remove item sequence 
      :count (- (count item sequence) n)
      :from-end from-end))

  (leave-at-most 2 #\a "bananas")  ==>  "banans"

  (leave-at-most 2 #\s "bananas")  ==>  "bananas"

 Fahlman suggests declaring "it is an error" for the value of :COUNT to be
negative.  This has the advantage of making all current implementations'
behavior legal, no matter how bizarre.  The disadvantages are that this
will be counterintuitive for beginners; it is less in keeping with the
spirit of the present wording of CLtL; and it will make functions such as
LEAVE-AT-MOST a little more complex, by requiring the user to throw a (MAX
0 ...) expression around the value of :COUNT.

Other things to consider:
 In the past there has been some argument about what SUBSEQ should do when
given positions greater than the length of the sequence.  Currently it "is
an error" to specify positions less than zero or greater than the length of
the sequence.  I don't think the same should apply to the :COUNT keyword.
The inputs to SUBSEQ are ordinal numbers: they specify positions, like
array subscripts.  The value of :COUNT is not an ordinal, it is an upper
bound on the size of the set of affected items (which is a cardinal

Cost of the change:  nonzero, but clearly trivial.  Given the current
wording of CLtL, no code can legally depend on the behavior of sequence
functions given negative values for :COUNT.  In practice it's unlikely
that many programs presently depend on one behavior or the other; if they
do then they're already non-portable.