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

go and return-from inside unwind-protect cleanup

    Date: Mon, 9 Sep 85 09:43 EDT
    From: David C. Plummer in disguise <DCP@SCRC-QUABBIN.ARPA>

    Are the following legal?

	    (defun foo (go-p)
	      (prog nil
			(return (compute))
		      (if go-p (go tag)))))

	    (defun bar (return-p)
	      (prog nil
			(progn (compute)
			       (go tag))
		      (if return-p (return nil)))))

    I say no, because the unwind-protect could be usurping the values of the
    first form of unwind-protect (in the case of normal exit) or could be
    usurping a THROW (in the abnormal exit).  

    There is no mention of this in CLtL (in the unwind-protect section, at
    least).  If it is legal, would somebody please tell me what FOO does.

I regard both of these as completely legal.  (FOO NIL) and (BAR T) call
COMPUTE exactly once.  (FOO T) and (BAR NIL) call COMPUTE repeatedly.

These can be explained adequately in terms of continuations.
Informally, whenever some internal computational process that is
unwinding the stack (such as a RETURN, GO, or THROW) encounters an
UNWIND-PROTECT, it makes up a continuation that, when invoked, will
continue the stack-unwinding process and then perform whatever was to
occur after that (return a value, transfer to a tag, etc.).  The cleanup
forms of the UNWIND-PROTECT are then executed with that continuation as
their continuation (that is, the action to be taken when they have all
been evaluated and control "flows off the end" of the implicit PROGN.

In the case of the protected form of a PROGN completing, the continuation is
"return a value from the UNWIND-PROTECT", and that is the continuation to
be performed after the cleanup forms.

GO, RETURN, and CATCH are operations that discard their normal continuations,
and perform some other control action instead.

In FOO, therefore, the use of RETURN begins a stack unwinding.  Hitting
the UNWIND-PROTECT causes a "return the value of (COMPUTE) from the PROG"
continuation to be made up and used as the continuation for the expression
(IF GO-P (GO TAG)).  If GO-P is NIL, the IF exits normally, the
return-continuation is used, and the PROG is exited.  If GO-P is not NIL,
then the GO is executed, which discards its normal continuation, and so
it completely forgets that it was intending to return from the PROG.
Control is transfered to the tag.  (A cleanup form is not protected by
its own UNWIND-PROTECT, and so no other unusual actions occur before
transfer to the tag.)

After completing this analysis, I tried out routines FOO and BAR both in
Symbolics 3600 Common Lisp and in DEC VAX LISP.  In both implementations
both FOO and BAR behave exactly as I have described.