CLHS: Issue PUSHNEW-STORE-REQUIRED Writeup

#

## Issue PUSHNEW-STORE-REQUIRED Writeup

    Issue:              PUSHNEW-STORE-REQUIRED
    References:         PUSHNEW
    Related issues:     PUSH-EVALUATION-ORDER
                        SETF-GET-DEFAULT
    Category:           CLARIFICATION
    Edit history:       v1, 14 Feb 1991, Sandra Loosemore
                        v2, 26 Mar 1991, Sandra Loosemore (amendment from meeting)
    Status:             v2 (proposal UNSPECIFIED) accepted by X3J13, Mar 1991

    Problem description:

      The description of the PUSHNEW macro says contradictory things about
      whether the storing form for its place subform must or must not be
      evaluated in the situation where the <item> is already a member of
      the list.

      In CLtL, PUSHNEW is first described as:

        If the <item> is not already a member of the list (...), then the
        <item> is consed onto the front of the list, and the augmented list is
        stored back into <place> and returned; otherwise the unaugmented list
        is returned.

      This passage implies that PUSHNEW is effectively (modulo order of
      evaluation issues and keyword arguments):

        (if (not (member <item> <place>))
            (setf <place> (cons <item> <place>))
            <place>)

      which executes the storing form for <place> only if the member test
      fails.

      However, later on it's said that PUSHNEW is effectively (again modulo
      order of evaluation issues and keyword arguments):

        (setf <place> (adjoin <item> <place>))

      which executes the storing form for <place> unconditionally.

      So which of these two models for its expansion is correct?

    Proposal (PUSHNEW-STORE-REQUIRED:UNSPECIFIED):

      Clarify that it is not specified whether PUSHNEW executes the storing
      form for its <place> subform in the situation where the <item> is
      already a member of the list.

    Rationale:

      The store operation might be expensive and there's no point in doing
      it if the value being stored hasn't changed.  On the other hand, in
      some implementations PUSHNEW always does the store.

    Current Practice:

      In both Lucid and Allegro, PUSHNEW always does the store.

    Cost to Implementors:

      None.  No implementation is required to change.

    Cost to Users:

      Probably none.

    Cost of non-adoption:

      The description of PUSHNEW is confusing.

    Performance impact:

      Not doing the store when it's not necessary can speed things up.

    Benefits:

      The cost of non-adoption is avoided.

    Esthetics:

      PUSHNEW would be less confusing if we could just agree on one or
      the other of the two models as being correct and remove all mention
      of the other from its description in the standard.

    Discussion:

      There is a potential for generalization to other read-modify-write
      macros.  See the discussion section of issue SETF-GET-DEFAULT.

Copyright 1996-2005, LispWorks Ltd. All rights reserved.