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

Issue: SETF-MULTIPLE-STORE-VARIABLES



[Please note that I am no longer on the Cleanup mailing list, so any
discussion of this should Cc me explicitly.  Thanks.  --Pavel]

Issue:         SETF-MULTIPLE-STORE-VARIABLES

References:    CLtL, pp.93-107

Category:      ADDITION

Edit history:  Pavel, December 5, 1988, (Version 1)

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.

Proposal (SETF-MULTIPLE-STORE-VARIABLES:ALLOW): Extend the semantics of the
macros SETF, PSETF, SHIFTF, ROTATEF, ASSERT, CTYPECASE, and CCASE to allow
"places" whose SETF methods have more than one "store variable".  In such
cases, the macros must arrange to save enough of the values of those
expressions whose result(s) will be assigned to a generalized-variable
reference.

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

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.

Current practice:

I do not know of any implementations that allow 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.

Cost to Implementors:

A relatively minor fix to each of the affected macros suffices.  For
example, to fix SETF itself, one need only check for the case of multiple
store variables and emit a MUTLIPLE-VALUE-BIND instead of a LET when there
is more than one to bind.

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.