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

Re: Issue: SETF-MULTIPLE-STORE-VARIABLES (Version 1)



On the whole I am for the idea of SETF and some of its friends handling
multiple values.  (I have implemented setf -- twice -- with an eye
towards such "upwards-compatible" extensions.)  However, there are a few
problems with the meanings of some of the constructs which are mentioned
when multiple values get added, and the argument about
GET-SETF-METHOD-MULTIPLE-VALUE being a non-uniformity and unneeded is
unsound.

    Date: Mon, 05 Dec 88 18:22:59 PST
    From: Pavel.pa@Xerox.COM

    [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.

SETF and PSETF are trivial, and their meanings are obvious, because
multiple "setfs" within the form are basically independent of each
other.  SHIFTF and ROTATEF may want to require all the places involved
to deal with the same number of multiple values, but probably for
consistency with multiple-value handling elsewhere, should just quietly
use NIL for missing values.

ASSERT, CTYPECASE, and CCASE on the other hand should NOT deal with
multiple values.  Semantically, they are dealing with individual values
(in the case of ASSERT, it is a list of individual values which can be
respecified by the user -- individually).

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

I see no problem with this.

    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.

See end of reply.

    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.

SHIFTF and ROTATEF get hairy (I punted), but I believe they are doable.

    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).

See end of reply.

    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.

See below.

    Discussion:

    Pavel supports this proposal.

The use and distinction of GET-SETF-METHOD and
GET-SETF-METHOD-MULTIPLE-VALUE is quite clear:  the latter is the
general case, and the former is for those contexts where multiple values
are not handled.  As such, it SHOULD give an error -- otherwise, the
poor caller that is not going to be able to deal with multiple values
(consider calls from setf methods like LDB and GETF) will only have to
check for it themselves.  It just happens that there are no predefined
setf-methods in CL specified by the manual.  In fact, a reading of the
manual implies that -- should a user correctly define a setf method on
VALUES -- it should work with SETF, and I don't believe it precludes
correct handling of multiple values by any of the other setting forms
(PSETF, SHIFTF, and ROTATEF) other than by use of PROG1 in descriptive
examples.

I would support a proposal which proposed the following:

Clarification that SETF and PSETF do handle multiple values.

Clarification of whether or not SHIFTF and ROTATEF do.  If they should,
the possibility of enforcement of all the place forms having the same
number of values arises.  I think they should handle multiple values and
should barf if they try to handle different numbers of values from
different places, but haven't thought about it a whole lot and don't
feel particularly strongly about it.

Addition of a builtin setf-method for the VALUES function.

Clarification of GET-SETF-METHOD to say that it signals an error if the
setf method returns other than one store variable.  I believe this to be
a clarification, taking into account the wording under
GET-SETF-METHOD-MULTIPLE-VALUE, and considering what other courses of
action it could take.  (Does it just throw them away for instance and
quietly let one construct broken code?  Does it not live up to the
"guarantee" it is documented to provide?)