407 lines
28 KiB
HTML
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 & 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 & 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 "evaluation" of the subforms, and other computations that are implicit<P>
|
|
in the notion of "doing an access" or "doing a store".<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 "binding the <P>
|
|
temporaries."<P>
|
|
<P>
|
|
<A REL=DEFINITION HREF="../Body/v__stst_.htm#STST"><B>**</B></A> It "reads the value" from the generalized variable using the supplied <P>
|
|
accessing form, to get the "old value"; this will be called "doing the<P>
|
|
access." [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 "storing <P>
|
|
form". This will be called "doing the store."<P>
|
|
<P>
|
|
"Reading the value" 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 <place> 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 <place-form> <bit-name>) <value-form>)<P>
|
|
<P>
|
|
the place referred to by the <place-form> must always be both accessed <P>
|
|
and updated; note that the update is to the generalized variable <P>
|
|
specified by <place-form> -- 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 <place-form><P>
|
|
2. Evaluate <bit-name> (and bind into a temporary)<P>
|
|
3. Evaluate <value-form> (and bind into the store variable)<P>
|
|
4. Do the access to <place-form><P>
|
|
5. Do the store into <place-form>, 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 <value-form> in step 3 alters what is found in the <P>
|
|
given "place" -- such as setting a different "bit" of the character --<P>
|
|
then the change of the bit denoted by <bit-name> will be to that altered<P>
|
|
character, because the "access" step is done after the <value-form><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> <byte-spec> <place-form>) <value-form>)<P>
|
|
<P>
|
|
the place referred to by the <place-form> must always be both accessed <P>
|
|
and updated; note that the update is to the generalized variable <P>
|
|
specified by <place-form> -- 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 <byte-spec> (and bind into a temporary)<P>
|
|
2. Bind the temporaries for <place-form><P>
|
|
3. Evaluate <value-form> (and bind into the store variable)<P>
|
|
4. Do the access to <place-form><P>
|
|
5. Do the store into <place-form> 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 <value-form> in step 3 alters what is found in the <P>
|
|
given "place" -- such as setting a different bit-field of the integer --<P>
|
|
then the change of the bit-field denoted by <byte-spec> will be to that <P>
|
|
altered integer, because the "access" step is done after the <value-form><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> <place-form> <ind-form>) <value-form>)<P>
|
|
<P>
|
|
the place referred to by the <place-form> must always be both accessed <P>
|
|
and updated; note that the update is to the generalized variable <P>
|
|
specified by <place-form> -- 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 <place-form> <P>
|
|
2. Evaluate <ind-form> (and bind into a temporary)<P>
|
|
3. Evaluate the <value-form> (and bind into the store variable)<P>
|
|
4. Do the access to <place-form><P>
|
|
5. Do the store into <place-form> with a possibly-new property list<P>
|
|
obtained by combining the values from steps 2, 3, and 4. <P>
|
|
<P>
|
|
If the evaluation of <value-form> in step 3 alters what is found in the <P>
|
|
given "place" -- such as setting a different named property in the list,<P>
|
|
then the change of the property denoted by <ind-form> will be to that <P>
|
|
altered list, because the "access" step is done after the <value-form><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 "possibly-new property list" treats the <P>
|
|
implementation of property lists as a "black box" -- 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>
|
|
"possibly-new property list" must proceed as if it were a different copy<P>
|
|
needing to be stored back into the generalized variable.<P>
|
|
<P>
|
|
The "read-modify-write" 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 "place" 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)) ==> #\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 ==> #\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) ==> #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 ==> #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))) ==> (#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 ==> nil<P>
|
|
l2 ==> (#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 "2. Bind the temporaries <P>
|
|
;; for <place-form>", and this was done before the evaluation of the<P>
|
|
;; <value-form> which contains the (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> l1 nil). Note also that the<P>
|
|
;; step "4. Do the access to <place-form>" 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))) ==> (#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 ==> (#x77)<P>
|
|
l2 ==> (#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>
|
|
;; "2. Bind the temporaries for <place-form>", and even though this <P>
|
|
;; was done before the evaluation of the <value-form> 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 "do the access" 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)) => #x6A<P>
|
|
integer ==> #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)) => #x6B0<P>
|
|
integer => #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))) ==> (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)) ==> 6<P>
|
|
r ==> (b 6)<P>
|
|
s ==> (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 "4. Do the access<P>
|
|
;; to <place-form>" is performed, the evaluation of the <value-form><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)))) ==> ((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)) ==> 6<P>
|
|
r ==> nil<P>
|
|
s ==> ((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 "1. Bind the temporaries for <place-form>". 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 "slots" of 'x', even if these slots are <P>
|
|
implemented as bit-fields, getf-properties, and so on. Only by separating <P>
|
|
out evaluation from "generalized variable access", 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 "place specifiers"<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> ... <place>) and of (<A REL=DEFINITION HREF="../Body/f_getf.htm#getf"><B>GETF</B></A> <place> ...) will behave<P>
|
|
uniformly no matter the nature of the <place>.<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 "Cost of non-adoption"<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>
|
|
"the place referred to by the <place-form> must always be both <P>
|
|
accessed and updated; note that the update is to the generalized <P>
|
|
variable specified by <place-form>"<P>
|
|
is not intended to prevent optimizations that could occur when the<P>
|
|
code "knows" 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)) ==> (a a b c d)<P>
|
|
(delete 'a l) ==> (b c d)<P>
|
|
l ==> (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 "DELETE didn't do anything". 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 <place-form> 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 "value-producing" forms; in fact, "doing the access" 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 "Problem <P>
|
|
Description" is at first perplexing -- the "do the access" 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>
|