psetf

Discussion of Common Lisp
Post Reply
filfil
Posts: 12
Joined: Mon Aug 06, 2012 3:21 pm

psetf

Post by filfil » Fri Aug 10, 2012 7:17 am

Hi everyone,

in http://clhs.lisp.se/Body/m_setf_.htm, it says:

For psetf, if more than one pair is supplied then the assignments of new values to places are done in parallel. 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.

Unpredictable order?? :o I can't believe you can't predict the order of such a computer language function output!!

BUT, look at the examples in the same page:

(setq x (cons 'a 'b) y (list 1 2 3)) => (1 2 3)
(setf (car x) 'x (cadr y) (car x) (cdr x) y) => (1 X 3)
x => (X 1 X 3)
y => (1 X 3)

(setq x (cons 'a 'b) y (list 1 2 3)) => (1 2 3)
(psetf (car x) 'x (cadr y) (car x) (cdr x) y) => NIL
x => (X 1 A 3)
y => (1 A 3)


If psetf evaluations were done in parallel, I would expect x => (X 1 2 3), and not (X 1 A 3).

Does anyone know the magic and mysterious way to predict that unpredictable order?

Thank you

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: psetf

Post by ramarren » Fri Aug 10, 2012 8:00 am

filfil wrote: I can't believe you can't predict the order of such a computer language function output!!
In this context "unpredictable" means that it depends on the implementation and the state of the system as whole, which means that even if you can predict the order in some circumstances, programs depending on that order do not conform to the standard and therefore such programs failing if any of the circumstances change is a bug in the program and not in the language. For example, both implementations for machines that allow only serial memory writes that simulate the parallel assignment and implementations for machines capable of truly parallel assignments are allowed by the standard, but the execution flow of a conforming program should not depend on the type of a machine it runs on.
filfil wrote:If psetf evaluations were done in parallel, I would expect x => (X 1 2 3), and not (X 1 A 3).
Conses in Common Lisp are mutable, and in this example the cons bound to X is mutated to refer to symbol X and the cons chain (that is, a list) bound to Y, which is itself mutated to contain A in second position. Parallel assignment allows the A to be retrieved from the cons bound to X before it is mutated.

filfil
Posts: 12
Joined: Mon Aug 06, 2012 3:21 pm

Re: psetf

Post by filfil » Fri Aug 10, 2012 8:57 am

Thank you very much.

The last answer is quite difficult for me: I still have to study LISP very much!

sylwester
Posts: 133
Joined: Mon Jul 11, 2011 2:53 pm

Re: psetf

Post by sylwester » Fri Aug 10, 2012 9:40 am

Interesting feature. It's like Scheme only that side effects are from left to right :D
Since the standard undefines it it will probably be the same order for each time the same chunk of code is run on the same CL-implementation but the order might even change from one expression to another as a compiler optimization perhaps.

Code: Select all

(setq y (cons 'a 'b))
(psetf (car y) (car y) (car y) (cdr y) )
=> (a . b) or (b . b)?

(setq a '(a b c))
(setq d '(d e f))
(psetf (cdr a) d (cddr a) d)
=> (a d e f) or (a . #1=(d . #1#)) ?
Unpredictable (or any order) is usual a sign that compiler writers are given some space to do it in the most efficient order and a hint that even though it's predictable in your test every time, it might not be in a different environment.
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

pjstirling
Posts: 166
Joined: Sun Nov 28, 2010 4:21 pm

Re: psetf

Post by pjstirling » Fri Aug 10, 2012 10:22 am

PSETF and SETF are like LET and LET*, if you want to depend on the order, then use the second, and if not the first.

At a higher level, PSETF exists for the same reason as PROG1 (a variant of PROGN that returns the value of the FIRST form and not the last), writing programs that require these types of construct in a language that doesn't supply them requires that your program uses explicit temporary variables, which can make your program less obvious in its behaviour. You only use them when necessary. The trade-off is that the language is a little larger, so people who don't know what they do need to look them up, but aren't we all using lisp because we are happy with that?

edgar-rft
Posts: 226
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: psetf

Post by edgar-rft » Fri Aug 10, 2012 12:07 pm

The probably most obvious use-case for PSETF is swapping places.

Swapping with SETF doesn't work as expected:

Code: Select all

(let ((a 1) (b 2))
  (setf a b b a)
  (list a b))
=> (2 2)
Swapping with SETF either needs an extra dummy variable:

Code: Select all

(let ((a 1) (b 2) c)
  (setf c b b a a c)
  (list a b))
=> (2 1)
... or an extra PROG1:

Code: Select all

(let ((a 1) (b 2))
  (setf a (prog1 b (setf b a)))
  (list a b))
=> (2 1)
Swapping with PSETF works as expected with no extra stuff:

Code: Select all

(let ((a 1) (b 2))
  (psetf a b b a)
  (list a b))
=> (2 1)
- edgar

Post Reply