Common lisp: what is the return value of prog2?

Viewed 82

One would expect prog2 to differ from prog1 and progn in returning the result of evaluating the second expression instead of the first and last, respectively. However, the HyperSpec says something different (emphasis mine):

prog2 evaluates first-form, then second-form, and then forms, yielding as its only value the primary value yielded by first-form.

That would mean that prog2 would return the same (and, in fact, behave much) like prog1!

Interestingly, the examples in the HyperSpec confirm the expected rather than the specified behaviour:

(setq temp 1) =>  1
(prog2 (incf temp) (incf temp) (incf temp)) =>  3
temp =>  4
(prog2 1 (values 2 3 4) 5) =>  2

Is this a typo in the standard or am I missing something deeper?

2 Answers

This seems to be a known issue with the ANSI standard (the full list can be found on CLiki).

I have tested it with SBCL 2.0.1 as well as with a recent version of Allegro and in both cases it behaves as expected (rather than as specified):

CL-USER> (prog2
             (print "1st")
             (print "2nd")
           (print "3rd"))

"1st" 
"2nd" 
"3rd" 
"2nd"

Come to think of it, even the indentation seems to suggest so.

For interest, I can enter the following code into Portacle (Emacs / SLIME / SBCL):

(prog2
   (print "1st")
   (print "2nd")
   (print "3rd"))

I placed the cursor on prog2, and used key sequence M-.. This shows what SBCL is actually doing.

(sb-xc:defmacro prog2 (form1 result &body body)
  `(prog1 (progn ,form1 ,result) ,@body))

So SBCL is pattern matching on the forms supplied. The first parameter is form form1 and the second parameter is form result, anything else is called body. The function progn returns the value of form result whilst evaluating form1, and prog1 picks this value also whilst evaluating body.

Conclusion - it's doing the sensible thing, not what the Hyperspec says.

Related