CLHS: Issue SETF-MULTIPLE-STORE-VARIABLES Writeup

#

## Issue SETF-MULTIPLE-STORE-VARIABLES Writeup

    Issue:         SETF-MULTIPLE-STORE-VARIABLES

    References:    CLtL, pp.93-107
                   Lisp Pointers, v2n2, pp.27-41

    Category:      ADDITION

    Edit history:  Version 1,  5-Dec-88, Pavel
                   Version 2, 22-Mar-89, Moon, simplify, update from discussion

    Problem description:

      The description of GET-SETF-METHOD-MULTIPLE-VALUE on page 107 of CLtL
      states that there are no cases in Common Lisp that allow multiple values
      to be stored into a generalized variable.  This is seen by some as an
      arbitrary decision in light of the fact that a very reasonable semantics
      exists for multiple values being assigned by several Common Lisp macros,
      including SETF.  The rationale on page 103 of CLtL suggests that this
      decision might be changed in the future.

    Proposal (SETF-MULTIPLE-STORE-VARIABLES:ALLOW):

      Extend the semantics of the macros SETF, PSETF, SHIFTF, ROTATEF, and
      ASSERT to allow "places" whose SETF methods have more than one "store
      variable".  In such cases, the macros accept as many values from the
      newvalue form as there are store variables.  As usual, extra values
      are ignored and missing values default to NIL.

      Extend the long form of DEFSETF to allow the specification of more
      than one "store variable", with the obvious semantics.

      Clarify that GET-SETF-METHOD signals an error if there would be more
      than one store-variable.

    Test Cases/Examples:

      (defstruct region width height)

      (defun region-size (region)
         (values
            (region-width region)
            (region-height region)))

      (defsetf region-size (region) (width height)
         `(values
             (setf (region-width ,region) ,width)
             (setf (region-height ,region) ,height)))

      (setf my-reg (make-region :width 10 :height 20))
      => #S(REGION :WIDTH 10 :HEIGHT 20)

      (region-size my-reg)
      => 10
         20

      (setf (region-size my-reg) (values 30 40))
      => 30
         40

      (region-size my-reg)
      => 30
         40

    Rationale:

      This change removes an artificial restriction on the semantics of
      several Common Lisp macros, allowing a broader set of contexts in
      which generalized variables can be used.  For example, it is not
      difficult to write a reasonable SETF method for the VALUES function,
      yielding a powerful MULTIPLE-VALUE-SETF form:

            (setf (values (car a) (gethash b 'c) (aref d 13))
                  (some-hairy-computation))

      In the language as currently defined, this example would have to be
      written:

            (multiple-value-bind (x y z)
                                 (some-hairy-computation)
               (setf (car a)        x
                     (gethash b 'c) y
                     (aref d 13)    z))

      Many other (perhaps more compelling) examples of generalized variables
      holding more than one value can easily be imagined.  Their use,
      however, is severely discouraged by Common Lisp as defined in CLtL,
      since none of the built-in macros will accept them.

      The clarification of GET-SETF-METHOD makes explicit what is implied
      by CLtL (CLtL uses the word "guarantee", whose relationship to
      signalling of errors is unclear).

    Current practice:

      I do not know of any implementations that allow all of this extension.
      Xerox Lisp does not signal an error, but this is probably due to a bug
      in GET-SETF-METHOD.  Lucid signals an error in GET-SETF-METHOD.
      Symbolics Genera supports the proposal in SETF and PSETF, but not in
      SHIFTF, ROTATEF, and ASSERT.

    Cost to Implementors:

      A relatively minor fix to each of the affected macros suffices.  For
      example, to fix SETF itself, one need only call
      GET-SETF-METHOD-MULTIPLE-VALUE instead of GET-SETF-METHOD and emit a
      MULTIPLE-VALUE-BIND instead of a LET for binding the store variables.

    Cost to Users:

      This is an upward-compatible change; no user code must change.

    Cost of non-adoption:

      Yet another non-uniformity in the language, yet another piece of
      mechanism without a clear use (GET-SETF-METHOD-MULTIPLE-VALUE).

    Benefits:

      Wider applicability of a reasonably nice abstraction, the removal of
      an artificial prohibition.

    Aesthetics:

      People may disagree about whether this is a simplification or not.  I
      am firmly on the side that believes that such removal of
      non-uniformities is a simplifying force in the language.

    Discussion:

      Pavel supports this proposal.

      Moon supports this proposal except he is not sure about the
      inclusion of ASSERT.

      GSB suggests that this is a clarification rather than an addition,
      because the lack of any predefined setf-methods that use multiple
      store variables should not mean that SETF, etc. should not work with
      such a setf-method if the user defined one.  The problem is that CLtL
      examples such as the ones for SHIFTF on p.98 and the simplified
      definition for SETF on p.107 contradict this proposal, and might have
      been taken as specifications, rather than simplified examples, by
      some readers.

      Predefined SETF methods for such functions as VALUES, CONS, and VECTOR
      could have been proposed, but we refrained.  This proposal is necessary
      to allow the user to write such methods for himself, but if this
      proposal is adopted those setf-methods are very easy to write in
      a portable fashion.

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