Issue: READ-MODIFY-WRITE-EVALUATION-ORDERReferences: DEFINE-MODIFY-MACRO
DECF, INCF, POP, PUSH, PUSHNEW, REMF
Related issues: Issue SETF-SUB-METHODS
Issue PUSH-EVALUATION-ORDER
Category: Clarification, change
Edit history: v1, 17 Dec 1990, Sandra Loosemore
v2, 19 Feb 1991, Sandra Loosemore
Problem description:
Proposal SETF-SUB-METHODS:DELAYED-ACCESS-STORES states that "reading
the value" of a generalized variable reference is not part of the
series of evaluations that must be done in left-to-right order. That
issue only addressed the problem in the context of SETF places such
as GETF, LDB, and MASK-FIELD whose SETF methods include an implicit
read-modify-write operation on a nested place form.
There is a similar order-of-evaluation issue for explicit
read-modify-write macros such as INCF and those defined with
DEFINE-MODIFY-MACRO: if the access to the place is performed before
other arguments to the macro are evaluated, any side-effects of those
evaluations on the value of the place are lost.
In the case of SETF of GETF and friends, issue SETF-SUB-METHODS placed
constraints on the order of evaluation of subforms within the values
returned by GET-SETF-METHOD. In the case of INCF and friends, the
question is the order of evaluation in the expansion of the
read-modify-write macro.
Proposal READ-MODIFY-WRITE-EVALUATION-ORDER:DELAYED-ACCESS-STORES:
Clarify that the exception of "reading the value" of a generalized
variable reference from the series of evaluations that must be done in
left-to-right order applies to the read-modify-write macros DECF,
INCF, POP, PUSH, PUSHNEW, REMF, SHIFTF and all macros defined with
Specifically:
For DECF, INCF, POP, REMF, and all macros defined with
DEFINE-MODIFY-MACRO:
These macros are of the form
(<operator> <place> . <other-arguments>)
The order of evaluation should be:
- all subforms of the <place>, in the order specified by the second
value of GET-SETF-METHOD for that <place>
- the <other-arguments>, in left-to-right order
- the access to <place>
- the computation of the new value to be stored
- the store into <place>
For PUSH and PUSHNEW:
These macros are of the form
(<operator> <object> <place> . <other-arguments>)
The order of evaluation should be:
- the <object>
- all subforms of the <place>, in the order specified by the second
value of GET-SETF-METHOD for that <place>
- the <other-arguments>, in left-to-right order
- the access to <place>
- the computation of the new value to be stored
- the store into <place>
In other words, the subforms of the <place> argument and any other
argument subforms should be evaluated in left-to-right order, but the
actual access of the <place> happens after all of the subform evaluations
and just before the computation and store of the new value.
Examples:
These two examples parallel examples 6 and 7 (respectively) from
issue SETF-SUB-METHODS.
1. (setq r (list 'a 1 'b 2 'c 3))
(setf (getf r 'b) (progn (setq r nil) 6))
r => (b 6)
(setq r 5)
r => 1
In both cases, the place form that is the target of the read-modify-write
operation is the variable R. The access of this place is delayed until
the other subforms have been evaluated, so the value of R that is
read as part of the read-modify-write operation reflects the SETQ.
2. (setq s (setq r (list (list 'a 1 'b 2 'c 3))))
r => nil
s => ((A 1 B 6 C 3))
(incf (car r) (progn (setq r (list 0)) 1))
r => (0)
s => (6)
In both cases, the nested place form is the value of (CAR R). Note that
the SETQ does not affect the read-modify-write operation because the
value of R has already been saved in a temporary variable as part of
evaluating the subforms of the nested place form. The read-modify-write
operation applies to the CAR of this value.
Rationale:
This makes the rules for conceptual "read-modify-write" operations
consistent, regardless of whether or not the operation is specified by
a special-case SETF place (such as GETF) or a macro such as those
defined by DEFINE-MODIFY-MACRO.
Current Practice:
Neither Lucid CL nor Allegro CL implement this proposal. In both
implementations, the access to the place subform apparently happens in
its normal left-to-right order.
Cost to Implementors:
Small.
Cost to Users:
Hard to say. Some programs that depend on the strict left-to-right
order of evaluation now supported in some implementations may break,
but probably such programs are no more common than those that were
broken by the adoption of proposal SETF-SUB-METHODS:DELAYED-ACCESS-STORES.
Cost of non-adoption:
Read-modify-write macros such as INCF and macros defined with
DEFINE-MODIFY-MACRO continue to have the same problems with losing
multiple updates to the place that were solved for SETF of GETF by
adoption of SETF-SUB-METHODS:DELAYED-ACCESS-STORES.
Performance impact:
Probably not applicable.
Benefits:
The cost of non-adoption is avoided.
Esthetics:
Specifying the same order of evaluation rules for all conceptual
read-modify-write operations is better than arbitrarily having a
difference between those defined as special-case SETF places (like GETF)
and those defined as macros.
Discussion:
This proposal does not change the order of evaluation for the macros
ROTATEF, SHIFTF, ASSERT, CHECK-TYPE, CTYPECASE, and CCASE. These
macros all have their own peculiar order-of-evaluation rules already.