201 lines
13 KiB
HTML
201 lines
13 KiB
HTML
<!-- Common Lisp HyperSpec (TM), version 7.0 generated by Kent M. Pitman on Mon, 11-Apr-2005 2:31am EDT -->
|
|
<HTML>
|
|
<HEAD>
|
|
<TITLE>CLHS: Issue READ-MODIFY-WRITE-EVALUATION-ORDER Writeup</TITLE>
|
|
<LINK HREF="../Data/clhs.css" REL="stylesheet" TYPE="text/css" />
|
|
<META HTTP-EQUIV="Author" CONTENT="Kent M. Pitman">
|
|
<META HTTP-EQUIV="Organization" CONTENT="LispWorks Ltd.">
|
|
<LINK REL=TOP HREF="../Front/index.htm">
|
|
<LINK REL=COPYRIGHT HREF="../Front/Help.htm#Legal">
|
|
<LINK REL=DISCLAIMER HREF="../Front/Help.htm#Disclaimer">
|
|
<LINK REL=PREV HREF="../Issues/iss286_w.htm">
|
|
<LINK REL=UP HREF="../Issues/iss287.htm">
|
|
<LINK REL=NEXT HREF="../Issues/iss288_w.htm">
|
|
</HEAD>
|
|
<BODY>
|
|
<H1><A REV=MADE HREF="http://www.lispworks.com/"><IMG WIDTH=80 HEIGHT=65 ALT="[LISPWORKS]" SRC="../Graphics/LWSmall.gif" ALIGN=Bottom></A><A REL=TOP HREF="../Front/index.htm"><IMG WIDTH=237 HEIGHT=65 ALT="[Common Lisp HyperSpec (TM)]" SRC="../Graphics/CLHS_Sm.gif" ALIGN=Bottom></A> <A REL=PREV HREF="../Issues/iss286_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="../Issues/iss287.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="../Issues/iss288_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
|
|
|
|
<HR>
|
|
|
|
|
|
|
|
<H2>Issue READ-MODIFY-WRITE-EVALUATION-ORDER Writeup</H2>
|
|
|
|
<PRE><B>Issue:</B> <A HREF="iss287.htm">READ-MODIFY-WRITE-EVALUATION-ORDER</A><P>
|
|
<B>References:</B> <A REL=DEFINITION HREF="../Body/m_defi_2.htm#define-modify-macro"><B>DEFINE-MODIFY-MACRO</B></A><P>
|
|
<A REL=DEFINITION HREF="../Body/m_incf_.htm#decf"><B>DECF</B></A>, <A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>INCF</B></A>, <A REL=DEFINITION HREF="../Body/m_pop.htm#pop"><B>POP</B></A>, <A REL=DEFINITION HREF="../Body/m_push.htm#push"><B>PUSH</B></A>, <A REL=DEFINITION HREF="../Body/m_pshnew.htm#pushnew"><B>PUSHNEW</B></A>, <A REL=DEFINITION HREF="../Body/m_remf.htm#remf"><B>REMF</B></A><P>
|
|
Related issues: Issue <A HREF="iss312.htm">SETF-SUB-METHODS</A><P>
|
|
Issue <A HREF="iss279_m.htm">PUSH-EVALUATION-ORDER</A><P>
|
|
<B>Category:</B> Clarification, change<P>
|
|
<B>Edit history:</B> v1, 17 Dec 1990, Sandra Loosemore<P>
|
|
v2, 19 Feb 1991, Sandra Loosemore<P>
|
|
<P>
|
|
<P>
|
|
<B>Problem description:<P>
|
|
</B><P>
|
|
Proposal <A HREF="iss312.htm">SETF-SUB-METHODS:DELAYED-ACCESS-STORES</A> states that "reading<P>
|
|
the value" of a generalized variable reference is not part of the<P>
|
|
series of evaluations that must be done in left-to-right order. That<P>
|
|
issue only addressed the problem in the context of <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> places such<P>
|
|
as <A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A>, <A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>LDB</B></A>, and <A REL=DEFINITION HREF="../Body/f_mask_f.htm#mask-field"><B>MASK-FIELD</B></A> whose <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> methods include an implicit<P>
|
|
read-modify-write operation on a nested place form.<P>
|
|
<P>
|
|
There is a similar order-of-evaluation issue for explicit<P>
|
|
read-modify-write macros such as <A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>INCF</B></A> and those defined with<P>
|
|
DEFINE-MODIFY-MACRO: if the access to the place is performed before<P>
|
|
other arguments to the macro are evaluated, any side-effects of those<P>
|
|
evaluations on the value of the place are lost.<P>
|
|
<P>
|
|
In the case of <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> of <A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A> and friends, issue <A HREF="iss312.htm">SETF-SUB-METHODS</A> placed<P>
|
|
constraints on the order of evaluation of subforms within the values<P>
|
|
returned by GET-SETF-METHOD. In the case of <A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>INCF</B></A> and friends, the<P>
|
|
question is the order of evaluation in the expansion of the<P>
|
|
read-modify-write macro.<P>
|
|
<P>
|
|
<P>
|
|
<B>Proposal READ-MODIFY-WRITE-EVALUATION-ORDER:DELAYED-ACCESS-STORES:<P>
|
|
</B><P>
|
|
Clarify that the exception of "reading the value" of a generalized<P>
|
|
variable reference from the series of evaluations that must be done in<P>
|
|
left-to-right order applies to the read-modify-write macros <A REL=DEFINITION HREF="../Body/m_incf_.htm#decf"><B>DECF</B></A>,<P>
|
|
<A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>INCF</B></A>, <A REL=DEFINITION HREF="../Body/m_pop.htm#pop"><B>POP</B></A>, <A REL=DEFINITION HREF="../Body/m_push.htm#push"><B>PUSH</B></A>, <A REL=DEFINITION HREF="../Body/m_pshnew.htm#pushnew"><B>PUSHNEW</B></A>, <A REL=DEFINITION HREF="../Body/m_remf.htm#remf"><B>REMF</B></A>, <A REL=DEFINITION HREF="../Body/m_shiftf.htm#shiftf"><B>SHIFTF</B></A> and all macros defined with<P>
|
|
<A REL=DEFINITION HREF="../Body/m_defi_2.htm#define-modify-macro"><B>DEFINE-MODIFY-MACRO</B></A>.<P>
|
|
<P>
|
|
Specifically:<P>
|
|
<P>
|
|
For <A REL=DEFINITION HREF="../Body/m_incf_.htm#decf"><B>DECF</B></A>, <A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>INCF</B></A>, <A REL=DEFINITION HREF="../Body/m_pop.htm#pop"><B>POP</B></A>, <A REL=DEFINITION HREF="../Body/m_remf.htm#remf"><B>REMF</B></A>, and all macros defined with<P>
|
|
DEFINE-MODIFY-MACRO:<P>
|
|
<P>
|
|
These macros are of the form<P>
|
|
(<operator> <place> . <other-arguments>)<P>
|
|
The order of evaluation should be:<P>
|
|
- all subforms of the <place>, in the order specified by the second<P>
|
|
value of GET-SETF-METHOD for that <place><P>
|
|
- the <other-arguments>, in left-to-right order<P>
|
|
- the access to <place><P>
|
|
- the computation of the new value to be stored<P>
|
|
- the store into <place><P>
|
|
<P>
|
|
<P>
|
|
For <A REL=DEFINITION HREF="../Body/m_push.htm#push"><B>PUSH</B></A> and PUSHNEW:<P>
|
|
<P>
|
|
These macros are of the form<P>
|
|
(<operator> <object> <place> . <other-arguments>) <P>
|
|
The order of evaluation should be:<P>
|
|
- the <object><P>
|
|
- all subforms of the <place>, in the order specified by the second<P>
|
|
value of GET-SETF-METHOD for that <place><P>
|
|
- the <other-arguments>, in left-to-right order<P>
|
|
- the access to <place><P>
|
|
- the computation of the new value to be stored<P>
|
|
- the store into <place><P>
|
|
<P>
|
|
In other words, the subforms of the <place> argument and any other<P>
|
|
argument subforms should be evaluated in left-to-right order, but the<P>
|
|
actual access of the <place> happens after all of the subform evaluations<P>
|
|
and just before the computation and store of the new value.<P>
|
|
<P>
|
|
<P>
|
|
<B>Examples:<P>
|
|
</B><P>
|
|
These two examples parallel examples 6 and 7 (respectively) from<P>
|
|
issue <A HREF="iss312.htm">SETF-SUB-METHODS</A>.<P>
|
|
<P>
|
|
1. (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r (list 'a 1 'b 2 'c 3))<P>
|
|
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (<A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>getf</B></A> r 'b) (<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>progn</B></A> (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>) 6))<P>
|
|
r => (b 6)<P>
|
|
<P>
|
|
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r 5)<P>
|
|
(<A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>incf</B></A> r (<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>progn</B></A> (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r 0) 1))<P>
|
|
r => 1<P>
|
|
<P>
|
|
In both cases, the place form that is the target of the read-modify-write<P>
|
|
operation is the variable R. The access of this place is delayed until<P>
|
|
the other subforms have been evaluated, so the value of R that is<P>
|
|
read as part of the read-modify-write operation reflects the <A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>SETQ</B></A>.<P>
|
|
<P>
|
|
2. (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> s (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r (list (list 'a 1 'b 2 'c 3))))<P>
|
|
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (<A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>getf</B></A> (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A> r) 'b)<P>
|
|
(<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>progn</B></A> (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>) 6))<P>
|
|
r => nil<P>
|
|
s => ((A 1 B 6 C 3))<P>
|
|
<P>
|
|
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> s (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r (<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> 5)))<P>
|
|
(<A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>incf</B></A> (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A> r) (<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>progn</B></A> (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r (<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> 0)) 1))<P>
|
|
r => (0)<P>
|
|
s => (6)<P>
|
|
<P>
|
|
In both cases, the nested place form is the value of (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> R). Note that<P>
|
|
the <A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>SETQ</B></A> does not affect the read-modify-write operation because the<P>
|
|
value of R has already been saved in a temporary variable as part of<P>
|
|
evaluating the subforms of the nested place form. The read-modify-write<P>
|
|
operation applies to the <A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> of this value.<P>
|
|
<P>
|
|
<P>
|
|
<B>Rationale:<P>
|
|
</B><P>
|
|
This makes the rules for conceptual "read-modify-write" operations<P>
|
|
consistent, regardless of whether or not the operation is specified by<P>
|
|
a special-case <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> place (such as <A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A>) or a macro such as those<P>
|
|
defined by <A REL=DEFINITION HREF="../Body/m_defi_2.htm#define-modify-macro"><B>DEFINE-MODIFY-MACRO</B></A>.<P>
|
|
<P>
|
|
<P>
|
|
<B>Current Practice:<P>
|
|
</B><P>
|
|
Neither Lucid CL nor Allegro CL implement this proposal. In both<P>
|
|
implementations, the access to the place subform apparently happens in<P>
|
|
its normal left-to-right order.<P>
|
|
<P>
|
|
<P>
|
|
<B>Cost to Implementors:<P>
|
|
</B><P>
|
|
Small.<P>
|
|
<P>
|
|
<P>
|
|
<B>Cost to Users:<P>
|
|
</B><P>
|
|
Hard to say. Some programs that depend on the strict left-to-right<P>
|
|
order of evaluation now supported in some implementations may break,<P>
|
|
but probably such programs are no more common than those that were<P>
|
|
broken by the adoption of proposal <A HREF="iss312.htm">SETF-SUB-METHODS:DELAYED-ACCESS-STORES</A>.<P>
|
|
<P>
|
|
<P>
|
|
<B>Cost of non-adoption:<P>
|
|
</B><P>
|
|
Read-modify-write macros such as <A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>INCF</B></A> and macros defined with<P>
|
|
<A REL=DEFINITION HREF="../Body/m_defi_2.htm#define-modify-macro"><B>DEFINE-MODIFY-MACRO</B></A> continue to have the same problems with losing<P>
|
|
multiple updates to the place that were solved for <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> of <A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A> by<P>
|
|
adoption of <A HREF="iss312.htm">SETF-SUB-METHODS:DELAYED-ACCESS-STORES</A>.<P>
|
|
<P>
|
|
<P>
|
|
<B>Performance impact:<P>
|
|
</B><P>
|
|
Probably not applicable.<P>
|
|
<P>
|
|
<P>
|
|
<B>Benefits:<P>
|
|
</B><P>
|
|
The cost of non-adoption is avoided. <P>
|
|
<P>
|
|
<P>
|
|
<B>Esthetics:<P>
|
|
</B><P>
|
|
Specifying the same order of evaluation rules for all conceptual <P>
|
|
read-modify-write operations is better than arbitrarily having a <P>
|
|
difference between those defined as special-case <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> places (like <A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A>)<P>
|
|
and those defined as macros.<P>
|
|
<P>
|
|
<P>
|
|
<B>Discussion:<P>
|
|
</B><P>
|
|
This proposal does not change the order of evaluation for the macros<P>
|
|
<A REL=DEFINITION HREF="../Body/m_rotate.htm#rotatef"><B>ROTATEF</B></A>, <A REL=DEFINITION HREF="../Body/m_shiftf.htm#shiftf"><B>SHIFTF</B></A>, <A REL=DEFINITION HREF="../Body/m_assert.htm#assert"><B>ASSERT</B></A>, <A REL=DEFINITION HREF="../Body/m_check_.htm#check-type"><B>CHECK-TYPE</B></A>, <A REL=DEFINITION HREF="../Body/m_tpcase.htm#ctypecase"><B>CTYPECASE</B></A>, and <A REL=DEFINITION HREF="../Body/m_case_.htm#ccase"><B>CCASE</B></A>. These<P>
|
|
macros all have their own peculiar order-of-evaluation rules already.<P>
|
|
</PRE>
|
|
<HR>
|
|
|
|
<A REL=NAVIGATOR HREF="../Front/StartPts.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Starting Points]" SRC="../Graphics/StartPts.gif" ALIGN=Bottom></A><A REL=TOC HREF="../Front/Contents.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Contents]" SRC="../Graphics/Contents.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Master.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Index]" SRC="../Graphics/Index.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Symbol.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Symbols]" SRC="../Graphics/Symbols.gif" ALIGN=Bottom></A><A REL=GLOSSARY HREF="../Body/26_a.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Glossary]" SRC="../Graphics/Glossary.gif" ALIGN=Bottom></A><A HREF="../Front/X3J13Iss.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Issues]" SRC="../Graphics/Issues.gif" ALIGN=Bottom></A><BR>
|
|
|
|
<A REL=COPYRIGHT HREF="../Front/Help.htm#Legal"><I>Copyright 1996-2005, LispWorks Ltd. All rights reserved.</I></A><P>
|
|
</BODY>
|
|
</HTML>
|