[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Order of evaluation in PUSH (& PUSHNEW)

 In the form: (push (ref1) (car (ref2)))
It is unclear whether (ref1) should be evaluated before (ref2). 

CLtL, page 270 states:
" The *effect* of (PUSH Item Place) is *roughly* equivalent to
(SETF Place (CONS Item Place))
except that the latter would evaluate any subforms of Place twice
while PUSH takes care to evaluate them only once."

CLtL, in discussion of generalized variable accessors/modifiers,
page 99 states:
"Macros that manipulate generalized variables must guarentee the "obvious"
semantics: subforms of generalized-variable references are evaluated ...
in exactly the same order as they appear in the *source* program."

	[Is this the *definition* of "obvious" semantics...?]

PUSH is in the class of "Macros that manipulate generalized variables".
However, even though the *generalized-variable references*
are evaluated with the "obvious" semantics, should standard macros
necessarily evaluate *all* their arguments in the "obvious" order?

The problem is that PUSH is [almost] specified as a macro which expands 
 to something in which its args are not in the "obvious" source order.

Shall we just agree that PUSH does not follow the "obvious" semantics?

Lucic and Franz evaluate (ref2) then (ref1)
Symbolics evaluate (ref1) then (ref2)

> (macroexpand '(push (ref1) (car (ref2))))
((LAMBDA (#:G2) 
  ((LAMBDA (#:G1) (SET-CAR #:G2 #:G1)) 
   (CONS (REF1) (CAR #:G2)))) 

<cl> (macroexpand '(push (ref1) (car (ref2))))
(LET* ((#:G8 (REF2))
       (#:G7 (CONS (REF1) (CAR #:G8))))
  (EXCL::.INV-CAR #:G8 #:G7)) 

Command: (macroexpand '(push (ref1) (car (ref2))))
(LET* ((#:G5 (REF1))
       (#:G4 (REF2)))
  (SYS:RPLACA2 #:G4 (VALUES (CONS #:G5 (CAR #:G4)))))

Definitely one for the CL comittee.