Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SETF : Ambiguous?

10 views
Skip to first unread message

Rene de Visser

unread,
Nov 22, 2001, 3:43:54 AM11/22/01
to
Consider the following code

(let ((result nil) (tail nil))
(let ((temp (list 1)))

(setf result (setf tail temp)))

(let ((temp (list 2)))

(setf (cdr tail) (setf tail temp)))

(values result tail))

The result of this seems to depend on the evaluation of order of place and
newvalue in (setf place newvalue).

However I didn't see where the order of place and new value was defined in
the Hyperspec for SETF.

In CormanLisp this results in

(1)

(2 ... )

and in Lispworks

(1 2)

(2)

Rene.


Rene

unread,
Nov 22, 2001, 7:03:21 AM11/22/01
to

Erik Naggum

unread,
Nov 22, 2001, 10:21:16 AM11/22/01
to
* Rene_de...@hotmail.com (Rene)

| However I didn't see where the order of place and new value was defined in
| the Hyperspec for SETF.

There is nothing special about the evaluation order for setf. The
standard Common Lisp evaluation order is strictly left to right. Any
deviation from this is a serious bug.

(let ((x (list 1 2 3)))
(setf (cdr (progn (format t "First base!~&")
x))
(progn (format t "Second base!~&")
(list 3 5)))
x)

In a conforming Common Lisp implementation, this _must_ print First base!
and Second base! in that order and return (1 3 5).

///
--
Norway is now run by a priest from the fundamentalist Christian People's
Party, the fifth largest party representing one eighth of the electorate.
--
Carrying a Swiss Army pocket knife in Oslo, Norway, is a criminal offense.

Pierre R. Mai

unread,
Nov 22, 2001, 9:58:42 AM11/22/01
to
Rene_de...@hotmail.com (Rene) writes:

> Consider the following code
>
> (let ((result nil) (tail nil))
> (let ((temp (list 1)))
> (setf result (setf tail temp)))
> (let ((temp (list 2)))
> (setf (cdr tail) (setf tail temp)))
> (values result tail))
>
> The result of this seems to depend on the evaluation of order of place and
> newvalue in (setf place newvalue).
>
> However I didn't see where the order of place and new value was defined in
> the Hyperspec for SETF.

On a quick glance I didn't find exact wording that exactly prohibits
what Corman Lisp does, though several appeals to left-to-right order
of evaluation, and section 5.1.2.9 seem to suggest that the intent was
clearly that left-to-right order of evaluation of subforms would
extend to the new-value forms of setf as well:

<quote>
5.1.2.9 Other Compound Forms as Places

For any other compound form for which the operator is a symbol f, the
setf form expands into a call to the function named (setf f). The
first argument in the newly constructed function form is newvalue and
the remaining arguments are the remaining elements of place. This
expansion occurs regardless of whether f or (setf f) is defined as a
function locally, globally, or not at all. For example,

(setf (f arg1 arg2 ...) new-value)

expands into a form with the same effect and value as

(let ((#:temp-1 arg1) ;force correct order of evaluation
(#:temp-2 arg2)
...
(#:temp-0 new-value))
(funcall (function (setf f)) #:temp-0 #:temp-1 #:temp-2...))

A function named (setf f) must return its first argument as its only
value in order to preserve the semantics of setf.
</quote>

Yes, I know that this could be considered to be an example, which
isn't binding, and furthermore the section doesn't deal with setf of
cdr, which is handled elsewhere, so again technically this isn't
binding at all.

But it clearly suggests, and I'd guess user expectations to agree with
this, that the new-value form is evaluated after all sub-forms of
place have been evaluated from left-to-right. So unless an
implementor can make the case that this is a real burden on his
implementation, I think following that hint would be a good thing.
All implementations I tested seem to follow that interpretation,
producing (1 2) and (2), as I'd have expected.

I'd be glad if someone could locate some more exact wording in the
standard.

Regs, Pierre.

--
Pierre R. Mai <pm...@acm.org> http://www.pmsf.de/pmai/
The most likely way for the world to be destroyed, most experts agree,
is by accident. That's where we come in; we're computer professionals.
We cause accidents. -- Nathaniel Borenstein

Rene de Visser

unread,
Nov 22, 2001, 11:45:34 AM11/22/01
to
Noting that SETF is a macro,

Is it then the case then that all the standard macros in common lisp that
end up evaluating their arguements
make sure that these evaluations occur in a left to right direction w.r.t to
the original macro parameters?

Do people pay much attention to this when writing their own macros?
(I certainly haven't given any thought to this in the past when writing my
own macros.)

Rene.

"Erik Naggum" <er...@naggum.net> wrote in message
news:32154312...@naggum.net...

Erik Naggum

unread,
Nov 22, 2001, 1:41:51 PM11/22/01
to
* Rene de Visser

| Is it then the case then that all the standard macros in common lisp that
| end up evaluating their arguements make sure that these evaluations occur
| in a left to right direction w.r.t to the original macro parameters?

Yes.

| Do people pay much attention to this when writing their own macros?

If they are smart and know the language, they do.

| (I certainly haven't given any thought to this in the past when writing
| my own macros.)

Well, then you have written _really_ bad macros.

Kent M Pitman

unread,
Nov 22, 2001, 2:32:08 PM11/22/01
to
Erik Naggum <er...@naggum.net> writes:

> * Rene de Visser
> | Is it then the case then that all the standard macros in common lisp that
> | end up evaluating their arguements make sure that these evaluations occur
> | in a left to right direction w.r.t to the original macro parameters?
>
> Yes.
>
> | Do people pay much attention to this when writing their own macros?
>
> If they are smart and know the language, they do.
>
> | (I certainly haven't given any thought to this in the past when writing
> | my own macros.)
>
> Well, then you have written _really_ bad macros.

Actually, the more generous way to say this is that you have macros that
only you can use.

You can, of course, write macros that violate this convention and then make
sure your code is careful to call the macro in a way that doesn't trip
up any problem.

But you should never offer these to other people without a HUGE disclaimer.

Btw, the same is true for double-evaluation. Macros should never do
double-evaluation of arguments without that being a well-publicized
effect. (Things like LOOP or DO or DOTIMES for example, may doubly
evlauate their arguments since that's the whole function of iteration.
But the details are carefully documented. For that matter, LOOP and
associates [I hesitate to call LOOP and DO friends :-] might be
considered to violate left to right evaluation, since it backs up
sometimes, but again, it doesn't happen casually.)

Kent M Pitman

unread,
Nov 22, 2001, 2:38:11 PM11/22/01
to
"Pierre R. Mai" <pm...@acm.org> writes:

> Rene_de...@hotmail.com (Rene) writes:
>
> > Consider the following code
> >
> > (let ((result nil) (tail nil))
> > (let ((temp (list 1)))
> > (setf result (setf tail temp)))
> > (let ((temp (list 2)))
> > (setf (cdr tail) (setf tail temp)))
> > (values result tail))
> >
> > The result of this seems to depend on the evaluation of order of place and
> > newvalue in (setf place newvalue).
> >
> > However I didn't see where the order of place and new value was defined in
> > the Hyperspec for SETF.

It's defined language-wide.

You should be looking for an exception in SETF, and none is given.

In CLTL, left-to-right order of evaluation failed to be mentioned
globally and people complained. It was mentioned in only three
places: SETF, DEFSETF, and the discussion of arithmetic contagion, all
of which were mentioned to "preserve the ordinary left-to-right order
of evaluation". Implementors fortunately inferred from that correctly
that there must be a left-to-right order globally. But for ANSI CL, we
moved those references to a central place.

The presence of heavy-duty mechanisms for those five setf-expansion values
should be proof enough of the intent in any case. It's extremely important
that this be correctly supported, to the point that we exposed to users
the same mechanism we expect the system to be using just to make sure it's
done consistently in all system and user code.

I'll look later perhaps. Gotta go eat some turkey.

Ian Wild

unread,
Nov 23, 2001, 6:02:05 AM11/23/01
to
"Pierre R. Mai" wrote:
>

> I'd be glad if someone could locate some more exact wording in the
> standard.

Quoth HyperSpec/Body/sec_5-1-1-1.html (rule 2):

"For the macros that manipulate places ...the subforms of the macro
call are evaluated exactly once in left-to-right order..."

Pierre R. Mai

unread,
Nov 23, 2001, 7:29:19 AM11/23/01
to
Ian Wild <i...@cfmu.eurocontrol.int> writes:

Right, that's the rule I had been missing. Thanks!

Thomas F. Burdick

unread,
Nov 25, 2001, 2:45:43 PM11/25/01
to
"Rene de Visser" <Rene_de...@hotmail.de> writes:

> Noting that SETF is a macro,
>
> Is it then the case then that all the standard macros in common lisp that
> end up evaluating their arguements
> make sure that these evaluations occur in a left to right direction w.r.t to
> the original macro parameters?
>
> Do people pay much attention to this when writing their own macros?
> (I certainly haven't given any thought to this in the past when writing my
> own macros.)

If I were you, I'd go through your commonly-used macros and fix this.
If you want to be consistent with Common Lisp, left-to-right order
should be used everywhere, except where the differing order of
evaluation is a part of the point of the macro. Even then, though, as
much should be done left-to-right as possible, because that will fit
with the instincts you acquire from CL.

You can probably get away with arbitrary orders of evaluation,
particularly if you hadn't thought about it, for a long time. Sort of
like how if you go and declare a bunch of commonly-used variables to
be special, you'll likely get by without being bitten for a long time.
But just like how working in a lisp image where X is special can
create some *really* confusing bugs when it finally catches up with
you, so will this. I screwed up left-to-right evaluation in a
commonly-used macro of mine through careless editing, and when I
finally got bitten by the bug, MAN did it take me too long to figure
out the problem.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

0 new messages