[racket] try/catch/finally idiom in Racket

304 views
Skip to first unread message

Sam Phillips

unread,
Oct 8, 2010, 7:32:44 PM10/8/10
to Racket List
Hi All,

I understand using call-with-exception-handler/with-handlers/etc. to
catch exceptions in a block of code, but I'm at a loss to what the best
way to do a "finally" or cleanup action after a block of code. My
intuition is to use dynamic-wind, but I figure there may be a better way
that I just cannot locate in the manual.

Is there a way to do this that I just cannot find?

Cheers,
Sam
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users

Jay McCarthy

unread,
Oct 8, 2010, 7:40:59 PM10/8/10
to Sam Phillips, Racket List
I use dynamic-wind for this. If there is something better, I don't
know what it is. dynamic-wind is a little bit funny though because if
you capture continuations then the in/out handlers can run multiple
times which might defy your expectations. You could set up a
continuation barrier on the inside to ensure that doesn't happen
though.

Jay

--
Jay McCarthy <j...@cs.byu.edu>
Assistant Professor / Brigham Young University
http://teammccarthy.org/jay

"The glory of God is Intelligence" - D&C 93

Neil Van Dyke

unread,
Oct 8, 2010, 8:20:49 PM10/8/10
to Jay McCarthy, Racket List
Should "racket/base" include something like "unwind-protect"?

The documentation could warn about what this restricts.

I feel bad every time I use "dynamic-wind" to approximate
"unwind-protect", pretending that I don't have first-order
continuations. But often I'm cleaning up one-shot external resources
anyway. "unwind-protect" would be more explicit about the assumptions
than "dynamic-wind" would, and incidentally would be tidier in the code.

Jay McCarthy wrote at 10/08/2010 07:40 PM:
> I use dynamic-wind for this. If there is something better, I don't know what it is. dynamic-wind is a little bit funny though because if you capture continuations then the in/out handlers can run multiple times which might defy your expectations. You could set up a continuation barrier on the inside to ensure that doesn't happen though.
>
>

--
http://www.neilvandyke.org/

Robby Findler

unread,
Oct 8, 2010, 8:25:08 PM10/8/10
to Neil Van Dyke, Jay McCarthy, Racket List
Probably you wanted a prompt in that case.

Robby

Neil Van Dyke

unread,
Oct 8, 2010, 8:31:09 PM10/8/10
to Robby Findler, Jay McCarthy, Racket List
OK, thanks. I will take a look at these continuation prompts. Don't
recall seeing them before.

Sam Phillips

unread,
Oct 8, 2010, 11:18:16 PM10/8/10
to Racket List, Jay McCarthy
On Fri, Oct 8, 2010 at 4:40 PM, Jay McCarthy <jay.mc...@gmail.com> wrote:
> I use dynamic-wind for this. If there is something better, I don't
> know what it is. dynamic-wind is a little bit funny though because if
> you capture continuations then the in/out handlers can run multiple
> times which might defy your expectations. You could set up a
> continuation barrier on the inside to ensure that doesn't happen
> though.

This is pretty much what I was afraid of with using dynamic-wind.

Zack Galler

unread,
Aug 10, 2011, 5:49:10 PM8/10/11
to us...@racket-lang.org
Sam Phillips <samdphillips@...> writes:

>
> Hi All,
>
> I understand using call-with-exception-handler/with-handlers/etc. to
> catch exceptions in a block of code, but I'm at a loss to what the best
> way to do a "finally" or cleanup action after a block of code. My
> intuition is to use dynamic-wind, but I figure there may be a better way
> that I just cannot locate in the manual.
>
> Is there a way to do this that I just cannot find?
>
> Cheers,
> Sam
>

Sam

Here's an implementation of the finally idiom.

Each line obtains the current continuation, stores it in 'out', then executes
buggy code implemented as (myerror n)

The handler-expression then invokes the continuation to continue evaluating the
remaining lines.

R./
Zack


define (myerror n)
(raise (exn:fail (format "threw error ~A\n" n) (current-continuation-marks))))

(let ((out #f))
(with-handlers ([exn:fail? (lambda (exn) (printf "~A\n" (exn-message exn))
(out))])
(let/cc k (set! out k) (myerror 1))
(let/cc k (set! out k) (myerror 2))
(let/cc k (set! out k) (myerror 3))
(let/cc k (set! out k) (myerror 4))
(let/cc k (set! out k) (myerror 5))))


output:

threw error 1

threw error 2

threw error 3

threw error 4

threw error 5

Zack Galler

unread,
Aug 10, 2011, 6:28:25 PM8/10/11
to us...@racket-lang.org
Sam Phillips <samdphillips@...> writes:

>
> On Fri, Oct 8, 2010 at 4:40 PM, Jay McCarthy <jay.mccarthy@...> wrote:
> > I use dynamic-wind for this. If there is something better, I don't
> > know what it is. dynamic-wind is a little bit funny though because if
> > you capture continuations then the in/out handlers can run multiple
> > times which might defy your expectations. You could set up a
> > continuation barrier on the inside to ensure that doesn't happen
> > though.
>
> This is pretty much what I was afraid of with using dynamic-wind.
>
> Cheers,
> Sam
>

Sam,
Followup to my earlier post.

Here's an unhygenic macro to execute the finally idiom

> (finally (myerror 1) (myerror 2) (myerror 3)(myerror 4))

output

threw error 1

threw error 2

threw error 3

threw error 4
=========================================================================
(require mzlib/defmacro)

(define-macro (finally . (fn . fns))
(let ((out (gensym))
(k (gensym)))
`(let* ((,out #f))


(with-handlers ([exn:fail? (lambda (exn) (printf "~A\n" (exn-message exn))

(,out))])
(let/cc ,k (set! ,out ,k) ,fn)
,@(map (lambda (f) `(let/cc ,k (set! ,out ,k) ,f)) fns)))))

Matthias Felleisen

unread,
Aug 12, 2011, 8:12:04 AM8/12/11
to Racket mailing list

dynamic-wind is the proper way to express 'finally' in Racket.

Neil Van Dyke

unread,
Aug 12, 2011, 9:36:48 AM8/12/11
to Racket Users List
Racket/Scheme language designers sometimes ask navel-gazing questions
like "What does it really mean to return a value?" -- asked
intelligently, not under the influence of psychoactives -- and this kind
of thinking soon leads to greater insight and to more powerful
programming language features.

You can certainly use "dynamic-wind" to approximate what Java people
think of as "finally", and that's what I usually do on a day-to-day
basis. But when we have the luxury of getting even smarter over
lunchtime, we can do things like read Dorai Sitaram's survey:
http://repository.readscheme.org/ftp/papers/sw2003/Unwind.pdf

--
http://www.neilvandyke.org/

Reply all
Reply to author
Forward
0 new messages