CLHS: Issue SETF-GET-DEFAULT Writeup

#

## Issue SETF-GET-DEFAULT Writeup

    Issue:             SETF-GET-DEFAULT
    References:        SETF of GET (CLtL-II p. 240)
                       SETF of GETF (CLtL-II p. 242)
                       SETF of GETHASH (CLtL-II p. 438)
    Related issues:    Issue PUSHNEW-STORE-REQUIRED
    Category:          CLARIFICATION
    Edit history:      V1, 12 Feb 1991, Sandra Loosemore

    Problem description:

      In the descriptions of SETF of GET, GETF, and GETHASH, it is stated
      that the optional default argument is ignored by SETF.  It is not
      clear whether this means that the *subform* corresponding to the
      default argument that is ignored, or only the *result* of evaluating
      the subform.  The behavior is distinguishable in situations where the
      subform has observable side-effects.

    Proposal (SETF-GET-DEFAULT:EVALUATED-BUT-IGNORED):

      Clarify that if the optional "default" argument is supplied in a call
      to GET, GETF, or GETHASH appearing as a SETF place, that subform
      is evaluated according to the normal left-to-right evaluation rules for
      subforms of a SETF place.  However, its value is ignored.

    Examples:

      #1: (setf (get 'foo 'message (print "hello world"))
                "goodbye, cruel world")
          => prints "hello world"

      #2: (let ((x  nil))
            (setf (getf x 'message (print "hello world"))
                  "goodbye, cruel world"))
          => prints "hello world"

      #3: (let ((x  (make-hash-table :test #'eq)))
            (setf (gethash 'message x (print "hello world"))
                  "goodbye, cruel world"))
          => prints "hello world"

    Rationale:

      Discarding the form corresponding to the default argument would be
      inconsistent with the rule that subforms of a SETF place are
      evaluated in left-to-right order.

    Current Practice:

      Lucid version 4.0 does tests 1 and 3 correctly but fails on test 2.
      Allegro version 3.1 performs all three tests correctly.
      Symbolics Genera reportedly fails at least test 2.

    Cost to Implementors:

      Minor.

    Cost to Users:

      None.

    Cost of non-adoption:

      Implementations will continue to differ for no good reason.

    Performance impact:

      None.

    Benefits:

      The language specification is made more precise and consistent.

    Esthetics:

      Making the language more consistent is a good thing.

    Discussion:

      Kent Pitman notes:

        Btw, someone (I think it was Allan Wechsler at Symbolics), that it
        should be permissible for:

         (LET ((X '(A 1 B 2)))
           (SETF (GETF X 'C 3) 3)
           X)
         => (A 1 B 2)

        because what the SETF -really- says is to make sure that (GETF X 'C 3)
        will later return 3, which that value of X does.  As such, I don't
        even think the code should be ignored.  I would prefer this
        interpretation if we could get consensus, and would appreciate your
        listing it as an option in your writeup, with me favoring it.  Two
        pieces of rationale you might add to the writeup are that (a) this
        permits an application to be more space-conservative and (b) this
        permits an application to not gratuitously modify pages of data that
        don't really need to be modified, and hence may sometimes result in
        smaller dumps or smaller working sets in some implementations that
        either permit dumping an incremental image containing only the
        modified pages, or that have an initial data set of copy-on-modify
        pages.

        As a fall-back, I think your clarification would be an improvement
        over the status quo.  But I think it's not as elegant.

      Sandra Loosemore says:

        I think we'd need to spec this out very carefully.  Should this
        behavior be required or simply permitted?  Does an explicit default
        of NIL do the same thing as no default?  Does only SETF of GETF
        behave this way, or should we generalize this to require/permit
        *any* SETF place not to actually update the place unnecessarily?
        In the general case, what predicate would be used to compare the
        new value to the value that would be returned by the accessor?
        While I agree this is an attractive idea on the surface, the more I
        think about these questions, the more I become convinced that this
        is an incompatible change and probably not a good idea overall.
    -------

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