From: Tim Bradshaw
Subject: Handling non-local returns in WITH-x forms
Date: 
Message-ID: <ey31y1tb9x0.fsf@cley.com>
Lots of (possibly naively-written) WITH-x forms expand to something
like this (gensyms replaced by interned symbols for readability):

(with-horrible-thing (x ...)
  ...code...)

-->

(let ((.x. ...)
      (.completed. nil))
 (unwind-protect
   (multiple-value-prog1
     (let ((x .x.))
       ...code...)
     (setf .completed. t))
   (if .completed.
       ...normal cleanup...
      ...abnormal cleanup...)))

But what if ...code... is (return-from outer-function 'done) or
something else that does a non-local, but non-error exit?  In that
case, this macro does the abnormal cleanup.

Can this easily be avoided?  Should it be?

--tim





 

From: Barry Margolin
Subject: Re: Handling non-local returns in WITH-x forms
Date: 
Message-ID: <e6x7a.30$PE4.739@paloalto-snr1.gtei.net>
In article <···············@cley.com>, Tim Bradshaw  <···@cley.com> wrote:
>Lots of (possibly naively-written) WITH-x forms expand to something
>like this (gensyms replaced by interned symbols for readability):
>
>(with-horrible-thing (x ...)
>  ...code...)
>
>-->
>
>(let ((.x. ...)
>      (.completed. nil))
> (unwind-protect
>   (multiple-value-prog1
>     (let ((x .x.))
>       ...code...)
>     (setf .completed. t))
>   (if .completed.
>       ...normal cleanup...
>      ...abnormal cleanup...)))
>
>But what if ...code... is (return-from outer-function 'done) or
>something else that does a non-local, but non-error exit?  In that
>case, this macro does the abnormal cleanup.
>
>Can this easily be avoided?  Should it be?

If you need to distinguish normal and abnormal cleanup, abnormal usually
means anything that didn't allow the ...code... to run all the way to
completion.  If you need to distinguish the *reason* why a non-local exit
occurred, then you need some variable that the application can control to
indicate what's going on.  E.g. instead of a hidden .completed. variable,
the macro could allow the caller to specify a variable to use.

(with-horrible-thing (x :completion-var successp ...)
  <body>)

-->

(let ((.x. ...)
      (successp nil))
  (unwind-protect
    (multiple-value-prog1
      (let ((x .x.))
        <body>)
      (setq successp t))
    (if successp <normal> <abnormal>)))

The <body> can contain (setq successp t) at any point to indicate which
type of cleanup should be done.

If the caller doesn't provide :completion-var, it can default to the hidden
variable.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, 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.
From: Tim Bradshaw
Subject: Re: Handling non-local returns in WITH-x forms
Date: 
Message-ID: <ey3smu9dvjx.fsf@cley.com>
* Barry Margolin wrote:

> If you need to distinguish normal and abnormal cleanup, abnormal
> usually means anything that didn't allow the ...code... to run all
> the way to completion.  If you need to distinguish the *reason* why
> a non-local exit occurred, then you need some variable that the
> application can control to indicate what's going on.  E.g. instead
> of a hidden .completed. variable, the macro could allow the caller
> to specify a variable to use.

Yes, this is kind of what I thought.  So really, for things like
WITH-OPEN-FILE it may not be safe to jump out half way through,
because that can legitimately cause a (close ... :abort t).

(I had code like:

(defun foo (...)
  (with-open-file (out ...)
    (loop
      (loop
        (more-complicated-nesting
         (when (we-are-done-now)
           (return-from foo t)))))))

and this left the file truncated sometimes...)

--tim