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

Issue: SETF-METHOD-FOR-SYMBOLS (alternate proposal)



I don't think this issue has anything to do with symbols.  For example,
consider the form

(setf (ldb (byte 8 0) x) (prog1 1 (setf (ldb (byte 8 8) x) 2)))

Suppose that X is 0.  This form now sets X to 1.  However, if X is
replaced with (CAR X), then the form will set (CAR X) to #x201.  In
order to have constant behavior, GETF and LDB must ALWAYS completely
evaluate their subform, whether it is a symbol or not.   If we do this
with all setf-methods then we might as well flush the idea of an
access-form since this must always be no more than a local variable
reference.   Furthermore the access-form must always be defined even
if the case is just SETF, because you will always access it as EB
points out in a previous message.

Furthermore, I think this behavior is unnatural.  Many applications
set up flag-words and the like, and a side-effect of computing a value
for one flag might well be the setting of another flag in the same
word.  In this case the same sub-place is being used to store various
objects, and there should be as little interaction between the setting
of the different objects as possible.

Therefore, I propose that we change the definition of a subform for
this order-of-evaluation issue and keep the methods on both pages 105
and 106.  See SETF-METHOD-FOR-SYMBOLS:CHANGE-MEANING-OF-SUBFORM below.


!

ISSUE:         SETF-METHOD-FOR-SYMBOLS

References:    CLtL pp. 105, 106, 99. Issue: PUSH-EVALUATION-ORDER.

Category:      CHANGE

Edit history:  Version 1 Moon 21 Sep 87
               Version 2 Masinter 23-Oct-87
               Version 3 Masinter 11-Nov-87
	       Version 4 KDO 4-Dec-87

Problem description:

The description of SETF in CLtL and various SETF methods are
inconsistent. The description on page 99 clearly requires side-effects
to be elaborated in left-to-right order; however, the combination of the
sample setf-method for LDB on p.106 and the sample setf-method for
symbols given on p. 105 results in incorrect order of evaluation. 

Test Case A: Given

(LET* ((R (LIST 'A 1 'B 2 'C 3))
       (S R))
  (SETF (GETF R 'B) (PROGN (SETQ R NIL) 6))
  (VALUES R S))

If side-effects are elaborated in left-to-right order, the setq of R to
NIL should not affect the result, since it occurs after R is read and
before R is written, and therefore the value of both R and S should be
(A 1 B 6 C 3).

A typical result in an implementation that believes CLtL p.105 more than
CLtL p.99 is R = (B 6) and S = (A 1 B 2 C 3).

Test Case B: Given:

(LET((A 0))
   (INCF (LDB (BYTE 2 2) A) (SETQ A 2))
   A)

Does this return 8, 10, or 2? If p. 99's description of order of
evaluation is correct, this should return 8.


It was pointed out that it is possible to get the required result for
the test case by modifying the get-setf-method for GETF (and other
setf-able items) to set up the bindings when the modified form is a
symbol, as is done in Spice Lisp. 

However, we believe that user programs are much more likely to have
copied the setf method for LDB given on p.106 than the setf method for
symbols schematized on p.105, and this is the simplest change to achieve
compatibility and correct behavior.


Proposal: SETF-METHOD-FOR-SYMBOLS:TEMPORARY-VARIABLE

Change the example of the result of

(GET-SETF-METHOD 'FOO) from
NIL NIL (#:G1174) (SETQ FOO #:G1174) FOO

(as currently described in CLtL) to return, for example,

(#:G1175) (FOO) (#:G1174) (SETQ FOO #:G1174) #:G1175

Rationale:

The general principle mentioned on p.99 should override the specific
example on p.105.  The latter is probably just a mistake.

Current practice:

Symbolics and Lucid return the incorrect result mentioned in the test
case A. (Symbolics plans to fix this in the next release.) Franz and
Xerox returns something else: R = nil and S = (a 1 b 6 c 3); Xerox
returns A=10 in Test Case B.   HP Common Lisp produces the recommended
value. 

Spice Lisp returns the recommended value for the test case A, even
though it uses the suggested value for the setf-method for symbols,
because the get-setf-method for GETF introduces additional temporary
bindings.

Adoption Cost:

SETF is an intricate part of Common Lisp, and the fact that not all
implementations currently return the same thing indicates that some care
might be required in updating implementations.  However, in some
implementations changing what get-setf-method returns when its argument
is a symbol is the only change required.

It's been pointed out that this change might cause less efficient code
to be produced in some cases, since setf methods will involve more
temporary variables, however Moon believes that the optimizations are
not difficult and probably are already done by most implementations.

Cost of non-adoption:

Users will think SETF is complicated and hard to understand, because
implementations won't conform to a simple general principle that
side-effects are elaborated in left-to-right order.

Benefits:

Improved portability of Common Lisp programs.

Conversion Cost:

This change is incompatible because it changes the result of some forms
that are not erroneous.  However, it's unlikely that very many users are
intentionally depending on the current behavior.  In addition, the
current behavior is not consistent across implementations, which makes
changing it less problematic.

Esthetics:

See "cost of non-adoption".

Discussion:

A specification of Common Lisp would do well to included some better
examples of precisely what is meant by the "`obvious' semantics"
mentioned on page 99.

This proposal is consistent with PUSH-EVALUATION-ORDER:ITEM in affirming
the left-right order of evaluation of subforms of generalized variable
access forms. 

It was pointed out that it is possible to get the required result for
the test case by modifying the get-setf-method for GETF (and other
setf-able items) to set up the bindings when the modified form is a
symbol, as is done in Spice Lisp. 

However, we believe that user programs are much more likely to have
copied the setf method for LDB given on p.106 than the setf method for
symbols schematized on p.105, and this is the simplest change to achieve
compatibility and correct behavior.


Proposal: SETF-METHOD-FOR-SYMBOLS:CHANGE-MEANING-OF-SUBFORM

Keep the old definition for symbols as examplified on p. 105 and the
definition for LDB on p. 106.  Specify that "subforms of
generalized-variable references" on p. 99 does not includes subforms
which will be stored into, but only those necessary to specify the
place to store.  In other words if the setf-method for a form must
recusively make use of the setf-method for a subform, that that
subform (but not any sub-subforms) is permitted to be evaluted at the
time of the store instead of in its lexical position.

Benefits:

Anyone who has copied examples from p.105 and p.106 will continue to
be able to use them.

Setf of (LDB ... X) will be consistant with (LDB ... (CAR X)) and all
other subplaces.

It is very unlikely that anyone is depending on the left-to-right
evaluation in this case, but quite possible that someone is depending
on the non-left-to-right evaluation for maintaining several bit-fields
in a symbol value.