[LISPWORKS][Common Lisp HyperSpec (TM)] [Previous][Up][Next]


Issue READ-MODIFY-WRITE-EVALUATION-ORDER Writeup

Issue:            READ-MODIFY-WRITE-EVALUATION-ORDER

References: 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

DEFINE-MODIFY-MACRO.

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)

(incf r (progn (setq r 0) 1))

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

(setf (getf (car r) 'b)

(progn (setq r nil) 6))

r => nil

s => ((A 1 B 6 C 3))

(setq s (setq r (list 5)))

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


[Starting Points][Contents][Index][Symbols][Glossary][Issues]
Copyright 1996-2005, LispWorks Ltd. All rights reserved.