[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

psetf specification ambiguity

Kaz Kylheku

5/13/2015 4:11:00 PM

According to the ANSI/CLHS description of PSETF, "the values in place1 through
placen are read and saved".

However, this does not completely pin down the possible range of behaviors.

The issue I'm perceiving is that:

- the places can all be evaluated first, and then their values can be sampled
and saved; or

- the sampling of the values can be interleaved with their evaluation such
that immediately after each place is evaluated, it is sampled; or

- some mixture of the above behaviors.

For instance if the places are (car x) (car y) and (car z), we can
have:

(let ((#:g010 x)
(#:g012 y)
(#:g014 z)) ;; the places are evaluated
;; now the storage locations are saved
;; (in a list, for illustration purposes)
(let ((#:g013 (list (car #:g010) (car #:g012) (car #:g014))))
...))

Or: interleaved:

(let ((#:g010 x) ;; evaluate place
(#:g011 (car #:g010)) ;; sample
(#:g012 y) ;; evaluate place
(#:g013 (car #:g012)) ;; sample
(#:g014 z)
(#:g015 (car #:g014)))
...)

Now, here it doesn't matter. But suppose that the expressions x, y and
z have side effects which modify the values of the places. Then it matters.

For example, suppose that the evaluation of form z affects (car #:g012).

In the first example, we sample (car #:g012) after evaluating z, whereas
in the second example we do it before.

Is this deliberately or accidentally unspecified?

Or is it specified according to some text elsewhere?
8 Answers

Kaz Kylheku

5/13/2015 4:13:00 PM

0

On 2015-05-13, Kaz Kylheku <kaz@kylheku.com> wrote:
> According to the ANSI/CLHS description of PSETF, "the values in place1 through
> placen are read and saved".

Sorry, the above text appears under SHIFTF, which is what this discussion
is intended to be about.

Pascal J. Bourguignon

5/13/2015 11:04:00 PM

0

Kaz Kylheku <kaz@kylheku.com> writes:

> According to the ANSI/CLHS description of PSETF, "the values in place1 through
> placen are read and saved".
>
> However, this does not completely pin down the possible range of behaviors.
>
> The issue I'm perceiving is that:
>
> - the places can all be evaluated first, and then their values can be sampled
> and saved; or
>
> - the sampling of the values can be interleaved with their evaluation such
> that immediately after each place is evaluated, it is sampled; or
>
> - some mixture of the above behaviors.
>
> For instance if the places are (car x) (car y) and (car z), we can
> have:
>
> (let ((#:g010 x)
> (#:g012 y)
> (#:g014 z)) ;; the places are evaluated
> ;; now the storage locations are saved
> ;; (in a list, for illustration purposes)
> (let ((#:g013 (list (car #:g010) (car #:g012) (car #:g014))))
> ...))
>
> Or: interleaved:
>
> (let ((#:g010 x) ;; evaluate place
> (#:g011 (car #:g010)) ;; sample
> (#:g012 y) ;; evaluate place
> (#:g013 (car #:g012)) ;; sample
> (#:g014 z)
> (#:g015 (car #:g014)))
> ...)
>
> Now, here it doesn't matter. But suppose that the expressions x, y and
> z have side effects which modify the values of the places. Then it matters.
>
> For example, suppose that the evaluation of form z affects (car #:g012).
>
> In the first example, we sample (car #:g012) after evaluating z, whereas
> in the second example we do it before.

> Is this deliberately or accidentally unspecified?
> Or is it specified according to some text elsewhere?

It is actually specified rather precisely:

More precisely, all subforms (in both the place and newvalue forms)
that are to be evaluated are evaluated from left to right; after all
evaluations have been performed, all of the assignments are
performed in an unpredictable order.

This means that all the side effects of the subforms occur from left to
right, before the places and values are considered for assignment. Once
the side effects have been computed, and the places and values have been
determined (in the order specified, therefore, unambiguously), then the
assignments can occur in any order. This matters only if two places are
the same:

(psetf x 1
x 2)

is not conforming,
because you may get either (assert (= x 1)) or (assert (= x 2)).

clall -r '(let (x) (psetf x 1 x 2) x)'

Armed Bear Common Lisp --> 2
Clozure Common Lisp --> 1
CLISP --> 1
CMU Common Lisp --> 2
ECL --> 2
SBCL --> 2


--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Pascal J. Bourguignon

5/13/2015 11:15:00 PM

0

Kaz Kylheku <kaz@kylheku.com> writes:

> On 2015-05-13, Kaz Kylheku <kaz@kylheku.com> wrote:
>> According to the ANSI/CLHS description of PSETF, "the values in place1 through
>> placen are read and saved".
>
> Sorry, the above text appears under SHIFTF, which is what this discussion
> is intended to be about.

It also says:

For information about the evaluation of subforms of places, see
Section 5.1.1.1 (Evaluation of Subforms to Places).

which specifies left-to-right evaluation of the subforms as in psetf.
Notably:

push, pushnew, remf, incf, decf, shiftf, rotatef, psetf, pop
evaluate all subforms before modifying any of the place
locations.

This leads to unambiguous operation:

clall -r '(let ((x (list 1))
(y (list 2))
(z (list 3)))
(shiftf (car (prog1 x (setf (car y) 0)))
(car (prog1 y (setf (car z) 0)))
(car (prog1 z)))
(values x y z))'

Armed Bear Common Lisp --> (0), (0), (0)
Clozure Common Lisp --> (0), (0), (0)
CLISP --> (0), (0), (0)
CMU Common Lisp --> (0), (0), (0)
ECL --> (0), (0), (0)
SBCL --> (0), (0), (0)


clall -r '(let ((x (list 1))
(y (list 2))
(z (list 3)))
(shiftf (car (prog1 x))
(car (prog1 y (setf (car x) 0)))
(car (prog1 z (setf (car y) 0))))
(values x y z))'

Armed Bear Common Lisp --> (2), (3), (3)
Clozure Common Lisp --> (2), (3), (3)
CLISP --> (2), (3), (3)
CMU Common Lisp --> (2), (3), (3)
ECL --> (2), (3), (3)
SBCL --> (2), (3), (3)

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Kaz Kylheku

5/13/2015 11:46:00 PM

0

On 2015-05-13, Pascal J. Bourguignon <pjb@informatimago.com> wrote:
> Kaz Kylheku <kaz@kylheku.com> writes:
>
>> On 2015-05-13, Kaz Kylheku <kaz@kylheku.com> wrote:
>>> According to the ANSI/CLHS description of PSETF, "the values in place1 through
>>> placen are read and saved".
>>
>> Sorry, the above text appears under SHIFTF, which is what this discussion
>> is intended to be about.
>
> It also says:
>
> For information about the evaluation of subforms of places, see
> Section 5.1.1.1 (Evaluation of Subforms to Places).
>
> which specifies left-to-right evaluation of the subforms as in psetf.

Thanks for investigating, Pascal.

Unfortunately, evaluation of the subforms of places doesn't establish
the timing of when their values are accessed---which need not happen
at all. For instance in (setf x y), the prior value of x is not accessed.

I'm not questioning evaluation order at all. Given

(shiftf a b c d e ... v)

it is clear that everything is evaluated left to right. For a place
to be evaluated, it means that the location to which it refers is
determined.

When evaluating the above shiftf, when do we retrieve and save the
old value of place a? We can do it immediately after evaluating a
(determining the location), before evaluating b. Or we can defer this
access after b is evaluated, or even after c, and so on.

One extreme is that the entire form is evaluated, and then places are accessed.
The other is that each place is accessed as soon as it is determined.

> Notably:
>
> push, pushnew, remf, incf, decf, shiftf, rotatef, psetf, pop
> evaluate all subforms before modifying any of the place
> locations.
>
> This leads to unambiguous operation:
>
> clall -r '(let ((x (list 1))
> (y (list 2))
> (z (list 3)))
> (shiftf (car (prog1 x (setf (car y) 0)))
> (car (prog1 y (setf (car z) 0)))
> (car (prog1 z)))
> (values x y z))'

Alas, yes, here, the behavior is clear, because each of your embedded side
effects refers to a *future* place (lexically to the right) that is not yet
evaluated at all, let alone accessed!

So as SHIFTF is evaluating the leftmost place

(car (prog1 x (setf (car y) 0)))

it hits a side effect in the form of the embedded (setf (car y) ...).
This side effect of course completes as part of the evaluation of this
form. So by the time the affected place is considered for the very first
time, its value is settled as zero.

The issue that I'm concerned with specifically affects the situation
that a SHIFTF place contains side effects within its subforms, and those
side effects affect another place *which lies to the left*, and which
has therefore already been evaluated (reduced to a determinant of
its location).

In other words, if you have a spare moment, please try this with your "clall":

clall -r '(let ((x (list 1))
(y (list 2))
(z (list 3)))
(shiftf (car (prog1 x))
(car (prog1 y (setf (car x) 0)))
(car (prog1 z (setf (car y) 0)))
;; One more form: clobber z for good measure, too:
(prog1 42 (setf (car z) 0))
(values x y z))'

Now it matters whether the value of (car (prog1 x)) is accessed and saved
immediately after that place is evaluated, or whether this access is
deferred. If it immediate, it will access 1; whereas if it is deferred
past the evaluation of the (car (prog1 y ...)) place, then it will access zero.

Kaz Kylheku

5/14/2015 12:03:00 AM

0

On 2015-05-13, Kaz Kylheku <kaz@kylheku.com> wrote:
> I'm not questioning evaluation order at all. Given
>
> (shiftf a b c d e ... v)
>
> it is clear that everything is evaluated left to right. For a place
> to be evaluated, it means that the location to which it refers is
> determined.
>
> When evaluating the above shiftf, when do we retrieve and save the
> old value of place a? We can do it immediately after evaluating a
> (determining the location), before evaluating b. Or we can defer this
> access after b is evaluated, or even after c, and so on.

Alas, this seems to be addressed by 5.1.3 "Treatment of Other Macros based on
SETF."

It is discussed in the associated X3J13 Cleanup Issue, which looks identical
to what I'm concerned about:

READ-MODIFY-WRITE-EVALUATION-ORDER:DELAYED-ACCESS-STORES

This agrees with me that accessing the prior value is not part of the
evaluation of a place, and resolves it by essentially proposing that
the prior values of places are read after the complete left-to-right
evaluation of all the arguments of the entire macro form.

All that is left which puzzles me is that SHIFTF is not mentioned in 5.1.3.
(However, it is talked about in the cleanup issue!)

???

It is clear that the rules are directly applicable to SHIFTF, and call for the
entire form to be evaluated, *then* the prior value of the places accessed and
saved, and then the shifting stores to take place.

Pascal J. Bourguignon

5/14/2015 2:38:00 AM

0

Kaz Kylheku <kaz@kylheku.com> writes:

> On 2015-05-13, Pascal J. Bourguignon <pjb@informatimago.com> wrote:
>> Kaz Kylheku <kaz@kylheku.com> writes:
>>
>>> On 2015-05-13, Kaz Kylheku <kaz@kylheku.com> wrote:
>>>> According to the ANSI/CLHS description of PSETF, "the values in place1 through
>>>> placen are read and saved".
>>>
>>> Sorry, the above text appears under SHIFTF, which is what this discussion
>>> is intended to be about.
>>
>> It also says:
>>
>> For information about the evaluation of subforms of places, see
>> Section 5.1.1.1 (Evaluation of Subforms to Places).
>>
>> which specifies left-to-right evaluation of the subforms as in psetf.
>
> Thanks for investigating, Pascal.
>
> Unfortunately, evaluation of the subforms of places doesn't establish
> the timing of when their values are accessed---which need not happen
> at all. For instance in (setf x y), the prior value of x is not accessed.
>
> I'm not questioning evaluation order at all. Given
>
> (shiftf a b c d e ... v)
>
> it is clear that everything is evaluated left to right. For a place
> to be evaluated, it means that the location to which it refers is
> determined.
>
> When evaluating the above shiftf, when do we retrieve and save the
> old value of place a? We can do it immediately after evaluating a
> (determining the location), before evaluating b. Or we can defer this
> access after b is evaluated, or even after c, and so on.
>
> One extreme is that the entire form is evaluated, and then places are accessed.
> The other is that each place is accessed as soon as it is determined.

Ok. 5.1.1.1 paragraph 2 says:

push, pushnew, remf, incf, decf, shiftf, rotatef, psetf, pop
evaluate all subforms before modifying any of the place locations.
^^^^^^^^^

Nothing is said about when the places are read. Notice that the side
effects of the places after the current place, cannot change the
place itself, only its value, given left-to-right evaluation of those
side effects. Therefore as soon as the side effects of the current
place are evaluated, the current place is determined and cannot change.

Indeed, the value of the current place can be modified by following side
effects, but since only the modifying of the places is specified to
occur after, I guess it's explicitely unspecified whether reading the
place may occur or not, and therefore such a form would be just
non-conforming.

Those forms:

clall -r '(let ((a (vector 1 2 3 4 5))
(i 0))
(shiftf (aref a 1)
(aref a 2)
(aref a (prog1 3
(setf (aref a 2) 0))))
a)'

Armed Bear Common Lisp --> #(1 3 4 4 5)
Clozure Common Lisp --> #(1 3 4 4 5)
CLISP --> #(1 3 4 4 5)
CMU Common Lisp --> #(1 3 4 4 5)
ECL --> #(1 3 4 4 5)
SBCL --> #(1 3 4 4 5)

shows that the place (aref a 2) is read before the side effect of the
third place is evaluated. Therefore, it seems like implementations do
perform the reading of places before evaluating the following side
effects.

I would have expected the side effects first, and the reading the places
next, which would give: #(1 0 4 4 5)

But this only shows that this shiftf form is not conforming: one should
not modify the place being modified by the shiftf in the side effects of
the places.

Similarly PSETF too is not implemented as I would have expected it:

clall -r '(let ((a (vector 1 2 3 4 5)))
(psetf (aref a 1) (aref a 2)
(aref a 2) (aref a (prog1 3 (setf (aref a 2) 0))))
a)'
Armed Bear Common Lisp --> #(1 3 4 4 5)
Clozure Common Lisp --> #(1 3 4 4 5)
CLISP --> #(1 3 4 4 5)
CMU Common Lisp --> #(1 3 4 4 5)
ECL --> #(1 3 4 4 5)
SBCL --> #(1 3 4 4 5)

but this form is non-conforming too.


> The issue that I'm concerned with specifically affects the situation
> that a SHIFTF place contains side effects within its subforms, and those
> side effects affect another place *which lies to the left*, and which
> has therefore already been evaluated (reduced to a determinant of
> its location).

Right.


> In other words, if you have a spare moment, please try this with your "clall":
>
> clall -r '(let ((x (list 1))
> (y (list 2))
> (z (list 3)))
> (shiftf (car (prog1 x))
> (car (prog1 y (setf (car x) 0)))
> (car (prog1 z (setf (car y) 0)))
> ;; One more form: clobber z for good measure, too:
> (prog1 42 (setf (car z) 0))
> (values x y z))'
>
> Now it matters whether the value of (car (prog1 x)) is accessed and saved
> immediately after that place is evaluated, or whether this access is
> deferred. If it immediate, it will access 1; whereas if it is deferred
> past the evaluation of the (car (prog1 y ...)) place, then it will access zero.

clall -r '(let ((x (list 1))
(y (list 2))
(z (list 3)))
(shiftf (car (prog1 x))
(car (prog1 y (setf (car x) 0)))
(car (prog1 z (setf (car y) 0)))
(prog1 42 (setf (car z) 0)))
(values x y z))'

Armed Bear Common Lisp --> (0), (3), (42)
Clozure Common Lisp --> (2), (3), (42)
CLISP --> (0), (3), (42)
CMU Common Lisp --> (0), (3), (42)
ECL --> (0), (3), (42)
SBCL --> (0), (3), (42)

My conclusion to answer your question is therefore that it's not
specified whether the place are read before or after the following side
effects, and therefore a form that has side effects modifying the values
of the places on the left is non-conforming.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Pascal J. Bourguignon

5/14/2015 2:41:00 AM

0

Kaz Kylheku <kaz@kylheku.com> writes:

> On 2015-05-13, Kaz Kylheku <kaz@kylheku.com> wrote:
>> I'm not questioning evaluation order at all. Given
>>
>> (shiftf a b c d e ... v)
>>
>> it is clear that everything is evaluated left to right. For a place
>> to be evaluated, it means that the location to which it refers is
>> determined.
>>
>> When evaluating the above shiftf, when do we retrieve and save the
>> old value of place a? We can do it immediately after evaluating a
>> (determining the location), before evaluating b. Or we can defer this
>> access after b is evaluated, or even after c, and so on.
>
> Alas, this seems to be addressed by 5.1.3 "Treatment of Other Macros based on
> SETF."
>
> It is discussed in the associated X3J13 Cleanup Issue, which looks identical
> to what I'm concerned about:
>
> READ-MODIFY-WRITE-EVALUATION-ORDER:DELAYED-ACCESS-STORES
>
> This agrees with me that accessing the prior value is not part of the
> evaluation of a place, and resolves it by essentially proposing that
> the prior values of places are read after the complete left-to-right
> evaluation of all the arguments of the entire macro form.
>
> All that is left which puzzles me is that SHIFTF is not mentioned in 5.1.3.
> (However, it is talked about in the cleanup issue!)
>
> ???
>
> It is clear that the rules are directly applicable to SHIFTF, and call for the
> entire form to be evaluated, *then* the prior value of the places accessed and
> saved, and then the shifting stores to take place.

Yes, but this is not what is implemented, cf. by previous message.
This issues hasn't been included in the standard.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

William James

5/14/2015 12:53:00 PM

0

Pascal J. Bourguignon wrote:

> This means that all the side effects of the subforms occur from left to
> right, before the places and values are considered for assignment. Once
> the side effects have been computed, and the places and values have been
> determined (in the order specified, therefore, unambiguously), then the
> assignments can occur in any order. This matters only if two places are
> the same:
>
> (psetf x 1
> x 2)


Gauche Scheme:

(let ((a 2) (b 3) (c 4))
(set!-values (a b c) (values c b a))
(list a b c))

===>
(4 3 2)

--
An important part of the explanation is the role of mass media in Sweden. Not a
single TV-program, radio program, or big newspaper would give space to critics
of the multicultural project.
fjordman.blogspot.ca/2005/05/is-swedish-democracy-collapsing.html