Skip to content

fix conflict with CL’s count function (GitLab issue #1)

Don Morrison requested to merge dmorrison/iterate:fix-count into master

Section 2.3 of the Iterate Manual, “Gathering Clauses,” states

These clauses all begin with a verb. When the verb does not conflict with an existing Common Lisp function, then it may be used in either its infinitival or present-participle form (e.g. sum, summing). However, when there is a conflict with Common Lisp, only the present-participle form may be used (e.g. unioning). This is to prevent iterate clauses from clashing with Common Lisp functions.

Unfortunately iterate currently uses the infinitival form of count, which is a Common Lisp function. For example,

(iter (for string in '("foo!" "bar!!" "baz?" "ba!zoo!"))
           (when (> (count #\! string) 1)
             (collect string)))

should return ("bar!!" "ba!zoo!"), but instead signals an error

Iterate, in (COUNT ! STRING):
Missing value for STRING keyword
   [Condition of type SIMPLE-ERROR]

According to its documentation, and to be consistent with other cases such as nconc or union, Iterate should use only counting, not count.

It is clear from the text of iterate.lisp that as originally written count correctly was not a synonym for counting, and only at some subsequent point was the buggy behavior introduced: in all the other cognate cases the defsynonym comes after the corresponding defclause, while it comes before for counting/count; in all the other cognate cases the defclause defines the infinitive form, with the present-participle being the target of the defsynonym, yet it is the other way around for counting/count; and count is not exported from the iterate package, as all other infinitive form used by iterate are.

Besides the simple (one line deletion) fix for this bug, I've also updated the unit tests:

  • I've add a new unit test, count.1, that will fail if this bug is at some point inadvertently re-introduced.
  • One of the unit tests amusingly contained a work around for this bug; I've backed out that work around.
  • Several of the unit tests used the infitival form; I have corrected them.

Prior to making this fix, running the unit tests resulted in five failures, all documented in iterate-tests.lisp. After making this fix no other tests fail.

I've only run the unit tests in SBCL, as I haven't been able to figure out how to get the test framework iterate uses to run elsewhere. However, I have informally confirmed that the fixed version does appear to behave fine in both CCL and CLISP.

Merge request reports