Having spent a lot of time "bullet-proofing" code recently,
it seems to me unwind-protect could use some help,
or perhaps could be rolled into exception handling?
Generally, my useage always seems to require knowing whether
the protected form completed or not, which requires a variable:
(let aborted = t
do
(unwind-protect
(progn
(do-something)
(set aborted = nil)
)
(if aborted
then ...
else ...)
)
Sure, one could write a macro to encapsulate the above pattern
(which I might argue should be the documented interface)
but the concern is the call to (do-something) can in fact return
but the variable not be set to nil, because there is some time
between the two forms. Thus, it seems that the processing
of the unwind-protect itself is where it will know if the
protected form was completed or not, and thus the low-level
implementation is where the variable should be set, not in user code.
In particular, interrupt handling can naturally occur on
function call/return, so using the above structure, on the return
from (do-something) is a natural break for an interrupt.
This leads me to wonder if in fact using some type of exception
handling is in fact more appropriate than unwind-protect,
and if so, then perhaps unwind-protect is obsolete,
and could just be implemented as a macro that uses exception
handling.
(with-handlers
(timeout ...) ;; only executed if the body times out or errors,
(error ...)
do
(do-something)
)
-Kelly Murray
In article <·················@IntelliMarket.Com>,
Kelly Murray <···@IntelliMarket.Com> wrote:
>Having spent a lot of time "bullet-proofing" code recently,
>it seems to me unwind-protect could use some help,
>or perhaps could be rolled into exception handling?
>
>Generally, my useage always seems to require knowing whether
>the protected form completed or not, which requires a variable:
Symbolic Common Lisp has a macro for this. I think it was something like:
(unwind-protect-case
<form>
(:if-success <forms>)
(:if-fails <forms>)
(:always <forms>))
The :if-success forms are executed if <form> runs to completion, :if-fails
if it doesn't, and :always are always executed.
--
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
Kelly Murray <···@IntelliMarket.Com> writes:
> This leads me to wonder if in fact using some type of exception
> handling is in fact more appropriate than unwind-protect,
> and if so, then perhaps unwind-protect is obsolete,
> and could just be implemented as a macro that uses exception
> handling.
Which kind of exceptions are you trying to protect against?
Asynchronous exceptions (like some Unix signals), or synchronous
exceptions (a.k.a. "conditions") ?
If you want your program to terminate some computation and
unwind the stack when it receives a _asynchronous_ exception,
you cannot do that by having the exception handler itself unwind
the stack. This simply will never be bullet-proof. Some
objects can always be left in an inconsistent state. (This
is also the reason why Java2 deprecates the function `Thread.stop').
Reacting safely on an asynchronous exception typically involves
a variable, which can be atomically set by the exception handler
when the exception occurred, and which is polled by the computation.
This way, an asynchronous exception is essentially transformed
into a synchronous one.
For _synchronous_ exceptions, on the other hand, `unwind-protect'
is perfectly appropriate.
> (let ((aborted t))
> (unwind-protect
> (progn
> (do-something)
> (setq aborted nil)
> )
> (if aborted
> (...)
> (...)
> )
> ) )
This is a fairly common idiom, and yes, a macro that encapsulates
it would be fine. And this is bullet-proof against synchronous
conditions, because between the return from `(do-something)' and
the following assignment, no exception can happen.
Bruno http://clisp.cons.org/~haible/