1
0
Fork 0
cl-sites/HyperSpec-7-0/HyperSpec/Issues/iss312_w.htm
2024-04-01 10:24:07 +02:00

407 lines
28 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 SETF-SUB-METHODS 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/iss311_w.htm">
<LINK REL=UP HREF="../Issues/iss312.htm">
<LINK REL=NEXT HREF="../Issues/iss313_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/iss311_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="../Issues/iss312.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="../Issues/iss313_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
<HR>
<H2>Issue SETF-SUB-METHODS Writeup</H2>
<PRE><B>Issue:</B> <A HREF="iss312.htm">SETF-SUB-METHODS</A><P>
<P>
<B>References:</B> CLtL pp. 95-96, 99, 105-106, 166<P>
Issue: <A HREF="iss279_m.htm">PUSH-EVALUATION-ORDER</A><P>
<P>
<B>Category:</B> CLARIFICATION<P>
<P>
<B>Edit history:</B> Version 1: JonL White &amp; Ken D. Olum 12-Feb-88<P>
(based on problem originally called SETF-METHOD-FOR-SYMBOLS)<P>
Version 2: JonL White 23-May-88 (fix references and spellings).<P>
Version 3: JonL White 25-May-88 <P>
Version 4: JonL White &amp; Ken D. Olum 26-May-88 (final insights!)<P>
Version 5: Masinter (respond to comments)<P>
<P>
<P>
<B>Problem description:<P>
</B><P>
Implementations differ in the left-to-right order<P>
of evaluation in the following form:<P>
<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r '(a 1 b 2 c 3))<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> s r)<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>
<P>
In some implementations, the side-effect of the <A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> appears to happen before<P>
the evaluation of the place form (<A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>getf</B></A> r 'b) which is necessary to fetch the <P>
list being updated. A typical result is 'r' = (B 6), 's' = (A 1 B 2 C 3)<P>
after the operation. <P>
<P>
There is a similar problem with <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A>'s over <A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>LDB</B></A>, <A REL=DEFINITION HREF="../Body/f_mask_f.htm#mask-field"><B>MASK-FIELD</B></A>, and CHAR-BIT.<P>
<P>
CLtL p99 is explicit about left-to-right order of evaluation.<P>
However, the specification is less clear about computations involved<P>
in &quot;evaluation&quot; of the subforms, and other computations that are implicit<P>
in the notion of &quot;doing an access&quot; or &quot;doing a store&quot;.<P>
<P>
Proposal: <A HREF="iss312.htm">SETF-SUB-METHODS:DELAYED-ACCESS-STORES</A><P>
<P>
This proposal specifies more explicilty the behavior of <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> in the case <P>
of access forms whose sub-forms are permitted to be generalized variable <P>
references [and which thus need to call GET-SETF-METHOD during <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> macro <P>
expansion].<P>
<P>
Remember, first, that GET-SETF-METHOD returns the following:<P>
<P>
-- Some temporary variables<P>
-- A list of value-producing forms<P>
-- A list of store-variables (normally one).<P>
-- A storing form.<P>
-- An accessing form.<P>
<P>
The code produced as the macro expansion of a <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> form that<P>
itself admits a generalized variable as an argument must essentially<P>
do the following major steps:<P>
<P>
<A REL=DEFINITION HREF="../Body/v__stst_.htm#STST"><B>**</B></A> It evaluates the value-producing sub-forms, in left-to-right order, and <P>
binds the temporary variables to them. This will be called &quot;binding the <P>
temporaries.&quot;<P>
<P>
<A REL=DEFINITION HREF="../Body/v__stst_.htm#STST"><B>**</B></A> It &quot;reads the value&quot; from the generalized variable using the supplied <P>
accessing form, to get the &quot;old value&quot;; this will be called &quot;doing the<P>
access.&quot; [Note that this is done after all the evaluations of the <P>
preceeding step, including any side-effects they may have.]<P>
<P>
<A REL=DEFINITION HREF="../Body/v__stst_.htm#STST"><B>**</B></A> It binds the store-variable to a new value, and then installs this<P>
new value into the generalized variable using the supplied &quot;storing <P>
form&quot;. This will be called &quot;doing the store.&quot;<P>
<P>
&quot;Reading the value&quot; of a generalized variable reference is not part of<P>
the series of evaluations that must be done in left-to-right order. <P>
<P>
The place-specifier forms listed at the top of CLtL p96 permit admit (other)<P>
place-specifiers as arguments; during the <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> expansion of these forms, it <P>
is necessary to call GET-SETF-METHOD in order to figure out how the inner, <P>
nested generalized variable must be treated. This proposal requires <A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A> be <P>
listed among these forms, since it must have a sub-recursive &lt;place&gt; specifier <P>
[however, there is no Common Lisp function serving as a pseudo-update function<P>
for it, the way <A REL=DEFINITION HREF="../Body/f_dpb.htm#dpb"><B>DPB</B></A> serves for LDB]. <P>
<P>
For each place-specifier form with a sub-recursive place specifier, <P>
the information from GET-SETF-METHOD is used as follows.<P>
<P>
CHAR-BIT:<P>
<P>
In a form such as:<P>
<P>
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> (CHAR-BIT &lt;place-form&gt; &lt;bit-name&gt;) &lt;value-form&gt;)<P>
<P>
the place referred to by the &lt;place-form&gt; must always be both accessed <P>
and updated; note that the update is to the generalized variable <P>
specified by &lt;place-form&gt; -- not to a character object itself.<P>
<P>
Thus this <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> should generate code to do the following:<P>
<P>
1. Bind the temporaries for &lt;place-form&gt;<P>
2. Evaluate &lt;bit-name&gt; (and bind into a temporary)<P>
3. Evaluate &lt;value-form&gt; (and bind into the store variable)<P>
4. Do the access to &lt;place-form&gt;<P>
5. Do the store into &lt;place-form&gt;, with the given bit-name of the <P>
character fetched in step 4 changed to reflect the value from step 3.<P>
<P>
If the evaluation of &lt;value-form&gt; in step 3 alters what is found in the <P>
given &quot;place&quot; -- such as setting a different &quot;bit&quot; of the character --<P>
then the change of the bit denoted by &lt;bit-name&gt; will be to that altered<P>
character, because the &quot;access&quot; step is done after the &lt;value-form&gt;<P>
evaluation. See example 1 in the test cases section. Nevertheless, the <P>
evaluations required for binding the temporaries are done in steps 1 and <P>
2, and thus the expected left-to-right evaluation order is seen.<P>
<P>
<P>
LDB: <P>
<P>
In a form such as:<P>
<P>
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> (<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>LDB</B></A> &lt;byte-spec&gt; &lt;place-form&gt;) &lt;value-form&gt;)<P>
<P>
the place referred to by the &lt;place-form&gt; must always be both accessed <P>
and updated; note that the update is to the generalized variable <P>
specified by &lt;place-form&gt; -- not to any object of type integer.<P>
<P>
Thus this <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> should generate code to do the following:<P>
<P>
1. Evaluate &lt;byte-spec&gt; (and bind into a temporary)<P>
2. Bind the temporaries for &lt;place-form&gt;<P>
3. Evaluate &lt;value-form&gt; (and bind into the store variable)<P>
4. Do the access to &lt;place-form&gt;<P>
5. Do the store into &lt;place-form&gt; with the given bit-field of the integer<P>
fetched in step 4 replaced with the value from step 3.<P>
<P>
If the evaluation of &lt;value-form&gt; in step 3 alters what is found in the <P>
given &quot;place&quot; -- such as setting a different bit-field of the integer --<P>
then the change of the bit-field denoted by &lt;byte-spec&gt; will be to that <P>
altered integer, because the &quot;access&quot; step is done after the &lt;value-form&gt;<P>
evaluation. See example 2 in the test cases section. Nevertheless, the <P>
evaluations required for binding the temporaries are done in steps 1 and <P>
2, and thus the expected left-to-right evaluation order is seen.<P>
<P>
<P>
MASK-FIELD:<P>
<P>
This case is the same as <A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>LDB</B></A> in all essential aspects.<P>
<P>
<P>
GETF:<P>
<P>
In a form such as:<P>
<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> &lt;place-form&gt; &lt;ind-form&gt;) &lt;value-form&gt;)<P>
<P>
the place referred to by the &lt;place-form&gt; must always be both accessed <P>
and updated; note that the update is to the generalized variable <P>
specified by &lt;place-form&gt; -- not necessarily to the particular list<P>
which is the property list in question.<P>
<P>
Thus this <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> should generate code to do the following:<P>
<P>
1. Bind the temporaries for &lt;place-form&gt; <P>
2. Evaluate &lt;ind-form&gt; (and bind into a temporary)<P>
3. Evaluate the &lt;value-form&gt; (and bind into the store variable)<P>
4. Do the access to &lt;place-form&gt;<P>
5. Do the store into &lt;place-form&gt; with a possibly-new property list<P>
obtained by combining the values from steps 2, 3, and 4. <P>
<P>
If the evaluation of &lt;value-form&gt; in step 3 alters what is found in the <P>
given &quot;place&quot; -- such as setting a different named property in the list,<P>
then the change of the property denoted by &lt;ind-form&gt; will be to that <P>
altered list, because the &quot;access&quot; step is done after the &lt;value-form&gt;<P>
evaluation. See example 7 in the test cases section. Nevertheless, the <P>
evaluations required for binding the temporaries are done in steps 1 and <P>
2, and thus the expected left-to-right evaluation order is seen.<P>
<P>
Note that this phrase &quot;possibly-new property list&quot; treats the <P>
implementation of property lists as a &quot;black box&quot; -- it can mean that <P>
the former property list is somehow destructively re-used, or it can <P>
mean partial or full copying of it. This is like the question of <A REL=DEFINITION HREF="../Body/f_rm_rm.htm#remove"><B>REMOVE</B></A><P>
or <A REL=DEFINITION HREF="../Body/f_rm_rm.htm#delete"><B>DELETE</B></A> -- do you copy or do you destructively alter. Since the answer<P>
could go either way, the treatment of the resultant value for the <P>
&quot;possibly-new property list&quot; must proceed as if it were a different copy<P>
needing to be stored back into the generalized variable.<P>
<P>
The &quot;read-modify-write&quot; macros such as <A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>INCF</B></A>, <A REL=DEFINITION HREF="../Body/m_incf_.htm#decf"><B>DECF</B></A>, <A REL=DEFINITION HREF="../Body/m_push.htm#push"><B>PUSH</B></A>, <A REL=DEFINITION HREF="../Body/m_pop.htm#pop"><B>POP</B></A>, <P>
and <A REL=DEFINITION HREF="../Body/m_remf.htm#remf"><B>REMF</B></A>, as well as <A REL=DEFINITION HREF="../Body/m_setf_.htm#psetf"><B>PSETF</B></A>, <A REL=DEFINITION HREF="../Body/m_shiftf.htm#shiftf"><B>SHIFTF</B></A>, and <A REL=DEFINITION HREF="../Body/m_rotate.htm#rotatef"><B>ROTATEF</B></A> should be <P>
specified to have the same evalauation order for the subforms of<P>
the &quot;place&quot; arguments; this would generally follow from their definition<P>
in terms of <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A>.<P>
<P>
<B>Test Cases:<P>
</B><P>
1. (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> char (make-char #\A 1)) ==&gt; #\Control-A<P>
(<A REL=DEFINITION HREF="../Body/m_rotate.htm#rotatef"><B>rotatef</B></A> (char-bit <A REL=DEFINITION HREF="../Body/f_char_.htm#char"><B>char</B></A> :control) <P>
(char-bit <A REL=DEFINITION HREF="../Body/f_char_.htm#char"><B>char</B></A> :meta)) <P>
char ==&gt; #\Meta-A<P>
;; It's as if you start with #\Control-A, and then first turn the<P>
;; :control bit off, because the :meta bit was originally off; and<P>
;; then to the resulting #\A, you add the :meta bit since the<P>
;; :control bit was originally on.<P>
<P>
Note, however, that if an implementation doesn't support both of these<P>
character 'bits', then this test case would have to be re-written to<P>
reference two independent bits actually supported. If an implementation<P>
supports fewer than two independent character bits, then this test case<P>
is entirely moot.<P>
<P>
2. (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> integer #x69) ==&gt; #x69<P>
(<A REL=DEFINITION HREF="../Body/m_rotate.htm#rotatef"><B>rotatef</B></A> (<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>ldb</B></A> (<A REL=DEFINITION HREF="../Body/f_by_by.htm#byte"><B>byte</B></A> 4 4) <A REL=DEFINITION HREF="../Body/t_intege.htm#integer"><B>integer</B></A>) <P>
(<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>ldb</B></A> (<A REL=DEFINITION HREF="../Body/f_by_by.htm#byte"><B>byte</B></A> 4 0) <A REL=DEFINITION HREF="../Body/t_intege.htm#integer"><B>integer</B></A>))<P>
integer ==&gt; #x96<P>
;; This very-realistic example is simply trying to swap two<P>
;; independent bit fields in an integer. Note that the generalized<P>
;; variable of interest here is just the (possibly local) program<P>
;; variable 'integer'.<P>
<P>
3a.(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l1 (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l2 (list #x69))) ==&gt; (#x69)<P>
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>ldb</B></A> (<A REL=DEFINITION HREF="../Body/f_by_by.htm#byte"><B>byte</B></A> 4 4) (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A> l1))<P>
(<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>ldb</B></A> (<A REL=DEFINITION HREF="../Body/f_by_by.htm#byte"><B>byte</B></A> 4 0) (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A> (<A REL=DEFINITION HREF="../Body/m_prog1c.htm#prog1"><B>prog1</B></A> l1 <P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l1 <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>))))) <P>
l1 ==&gt; nil<P>
l2 ==&gt; (#x99)<P>
;; Note that the (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l1 nil) didn't affect the actions of the <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A><P>
;; at all, since l1 was evaluated and its value was saved away in a<P>
;; temporary variable as part of the step &quot;2. Bind the temporaries <P>
;; for &lt;place-form&gt;&quot;, and this was done before the evaluation of the<P>
;; &lt;value-form&gt; which contains the (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l1 nil). Note also that the<P>
;; step &quot;4. Do the access to &lt;place-form&gt;&quot; means fetching the <A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> of<P>
;; the saved (temporary) value of 'l1'; it does not mean doing a <A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>LDB</B></A><P>
;; on anything like that.<P>
<P>
<P>
3b.(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l1 (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l2 (list #x69))) ==&gt; (#x69)<P>
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>ldb</B></A> (<A REL=DEFINITION HREF="../Body/f_by_by.htm#byte"><B>byte</B></A> 4 4) (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A> l1))<P>
(<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>ldb</B></A> (<A REL=DEFINITION HREF="../Body/f_by_by.htm#byte"><B>byte</B></A> 4 0) (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A> (<A REL=DEFINITION HREF="../Body/f_rplaca.htm#rplaca"><B>rplaca</B></A> l1 #x17))))<P>
l1 ==&gt; (#x77)<P>
l2 ==&gt; (#x77)<P>
;; Note that the (<A REL=DEFINITION HREF="../Body/f_rplaca.htm#rplaca"><B>rplaca</B></A> l1 #x17) altered the contents of what l1<P>
;; was pointing to. Thus even though l1 was evaluated and its <P>
;; value was saved away in a temporary variable as part of the step <P>
;; &quot;2. Bind the temporaries for &lt;place-form&gt;&quot;, and even though this <P>
;; was done before the evaluation of the &lt;value-form&gt; which contains <P>
;; the <A REL=DEFINITION HREF="../Body/f_rplaca.htm#rplaca"><B>rplaca</B></A>, still the side-effect changes things because it alters<P>
;; what will be fetched during the &quot;do the access&quot; step.<P>
<P>
4. (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> integer #x69)<P>
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (<A REL=DEFINITION HREF="../Body/f_mask_f.htm#mask-field"><B>mask-field</B></A> (byte 4 4) integer) (<A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>incf</B></A> integer)) =&gt; #x6A<P>
integer ==&gt; #x6A<P>
<P>
5. (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> integer #x6A)<P>
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (<A REL=DEFINITION HREF="../Body/f_mask_f.htm#mask-field"><B>mask-field</B></A> (byte 4 4) integer) (ash (<A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>incf</B></A> integer) 4)) =&gt; #x6B0<P>
integer =&gt; #xBB<P>
<P>
6. (<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 'a 1 'b 2 'c 3))) ==&gt; (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) <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 nil) 6)) ==&gt; 6<P>
r ==&gt; (b 6)<P>
s ==&gt; (a 1 b 2 c 3)<P>
;; Note that the generalized variable of concern here is the (degenerate?)<P>
;; one of simply the program variable 'r'; it is not a property-list <P>
;; slot denoted by (<A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>getf</B></A> r 'b). At the time the step &quot;4. Do the access<P>
;; to &lt;place-form&gt;&quot; is performed, the evaluation of the &lt;value-form&gt;<P>
;; has already altered the generalized variable 'r', and thus a nil is<P>
;; returned for this access; that is why a fresh property-list (B 6) is<P>
;; created an stored back into 'r'.<P>
<P>
7. (<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)))) ==&gt; ((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 nil) 6)) ==&gt; 6<P>
r ==&gt; nil<P>
s ==&gt; ((A 1 B 6 C 3))<P>
;; Note that the (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> r nil) does not affect the actions of the <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> <P>
;; because the value of R had already been saved in a temporary variable<P>
;; as part of the step &quot;1. Bind the temporaries for &lt;place-form&gt;&quot;. Only<P>
;; the <A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> of this value will be accessed, and subsequently modified <P>
;; after the value computation.<P>
<P>
<P>
<B>Rationale:<P>
</B><P>
As a principle,<P>
<P>
(<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (foo-a x) (<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>progn</B></A> (<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> (foo-b x) ...)<P>
new-a-value))<P>
<P>
should always set both of the &quot;slots&quot; of 'x', even if these slots are <P>
implemented as bit-fields, getf-properties, and so on. Only by separating <P>
out evaluation from &quot;generalized variable access&quot;, and by specifying that<P>
the access is done after all the evaluations, can this correctly be done.<P>
<P>
<B>Current Practice:<P>
</B><P>
Lucid Common Lisp already operates pretty much according to this proposal.<P>
Symbolics Genera 7.2 foolishly adopted an earlier proposal<P>
(SETF-METHOD-FOR-SYMBOLS) before it was officially approved by X3J13 and<P>
its parent standards organization. This proposal is incompatible with<P>
that one, so Genera 7.2 does not implement the behavior described here,<P>
and fails test cases 1, 2, 4, 5, and 6. Symbolics Genera 7.1<P>
is probably closer to this proposal. <P>
<P>
<B>Performance impact:<P>
</B><P>
Small. This proposal might slow down macro-expansion slightly,<P>
might cause some current optimizations not to work as well. However,<P>
the net effect is likely negligible.<P>
<P>
<B>Cost to Implementors:<P>
</B><P>
In some implementations, this would <A REL=DEFINITION HREF="../Body/f_provid.htm#require"><B>require</B></A> a careful revisiting of<P>
the handling of <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> and generalized variable modifiers.<P>
<P>
<B>Cost to Users:<P>
</B><P>
Small; although this will impose an incompatible change on <P>
implementations that don't behave as proposed, and might have<P>
an effect on (non-portable) code, we believe the effects<P>
are not widespread.<P>
<P>
<B>Cost of non-adoption:<P>
</B><P>
<A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A> left-to-right order of evaluation will not be well specified;<P>
implementations will differ for no good reason.<P>
<P>
<B>Benefits:<P>
</B><P>
Uniform semantics and portability in the face of recursive &quot;place specifiers&quot;<P>
for <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>SETF</B></A>. Setf of (<A REL=DEFINITION HREF="../Body/f_ldb.htm#ldb"><B>LDB</B></A> ... &lt;place&gt;) and of (<A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A> &lt;place&gt; ...) will behave<P>
uniformly no matter the nature of the &lt;place&gt;.<P>
<P>
Anyone who has copied examples from p105 and p106 will continue to<P>
be able to use them.<P>
<P>
<B>Esthetics:<P>
</B><P>
See &quot;Cost of non-adoption&quot;<P>
<P>
<B>Discussion:<P>
</B><P>
This is a difficult proposal to specify.<P>
<P>
In the detailed descriptions for each access form, the phrase<P>
&quot;the place referred to by the &lt;place-form&gt; must always be both <P>
accessed and updated; note that the update is to the generalized <P>
variable specified by &lt;place-form&gt;&quot;<P>
is not intended to prevent optimizations that could occur when the<P>
code &quot;knows&quot; that the new value will be <A REL=DEFINITION HREF="../Body/f_eq.htm#eq"><B>EQ</B></A> to the old one. The only<P>
requirements is that the results be semantically equivalent.<P>
<P>
There is an interesting parallel between this case for <A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A> and the<P>
very common mistake made by Lisp programmers with respect to the <P>
function <A REL=DEFINITION HREF="../Body/f_rm_rm.htm#delete"><B>DELETE</B></A>. How often the complaint is filed that <A REL=DEFINITION HREF="../Body/f_rm_rm.htm#delete"><B>DELETE</B></A> didn't<P>
do anything when it should have; but in fact the filer simply forgot<P>
that delete, although permitted to destructively modify the original<P>
list, may also return some tail of the list originally give it, <P>
whether or not an alteration occurs.<P>
<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l '(a a b c d)) ==&gt; (a a b c d)<P>
(delete 'a l) ==&gt; (b c d)<P>
l ==&gt; (a a b c d)<P>
<P>
The unwary user thinks that because 'l' is still <A REL=DEFINITION HREF="../Body/f_eq.htm#eq"><B>EQ</B></A> to the original value <P>
that &quot;DELETE didn't do anything&quot;. The temptation to ignore the resultant <P>
value of <A REL=DEFINITION HREF="../Body/f_rm_rm.htm#delete"><B>DELETE</B></A> parallels the temptation to forget about a need to perform<P>
a final update to &lt;place-form&gt; in the setf-of-getf case.<P>
<P>
In the (degenerate?) case when a generalized variable <P>
is in fact simply a program variable, then there are no sub-forms to be<P>
considered &quot;value-producing&quot; forms; in fact, &quot;doing the access&quot; for such<P>
a generalized variable (i.e. a program variable) is functionally the<P>
same as evaluating it. This explains why the behaviour in the &quot;Problem <P>
Description&quot; is at first perplexing -- the &quot;do the access&quot; step has the same<P>
semantics as an evaluation step, even though it is done after all the<P>
prescribed evaluations.<P>
<P>
The issue <A HREF="iss279_m.htm">PUSH-EVALUATION-ORDER</A> is a clarification about just the point<P>
of the evaluation order for the various subforms to a PUSH; thus there<P>
is a similarity to this issue, but the present issue has a much deeper<P>
problem because of the need to call GET-SETF-METHOD during <A REL=DEFINITION HREF="../Body/a_setf.htm#setf"><B>setf</B></A> macro<P>
expansion.<P>
<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>