Awesome! Thanks. And I can't think of a better way. This is ultimately the same problem found in this sort of code:
(let [something-we-need-to-close (open whatever)] (try (something-lazy something-we-need-to-close) (finally (close something-we-need-to-close)))) This was discussed recently on another thread, but I forget which. On Wed, Feb 25, 2009 at 9:26 PM, Chouser <chou...@gmail.com> wrote: > > On Wed, Feb 25, 2009 at 12:32 PM, Chouser <chou...@gmail.com> wrote: > > On Wed, Feb 25, 2009 at 9:05 AM, Jeffrey Straszheim > > <straszheimjeff...@gmail.com> wrote: > >> Does the stuff in error kit work across thread boundaries. I'm > thinking, > >> for instance, if you run a computation using pmap, the individual > >> computations are run inside of Java futures, which will propagate > exceptions > >> back to the caller when the caller gets the value. So, pmap should work > >> fairly transparently with regard to Java exception semantics. That is > nice. > > > > That's a very interesting scenario, thanks for bringing it up. > > > >> Can the same be said for the error-kit stuff? > > > > Currently, no. The problem is that though future propagates > > exceptions on the way out, it does not propagate dynamic binding > > context on the way in, which is what error-kit needs to do what it > > does. Also, error-kit uses some thread-local data to pass information > > up the stack past frames that don't know about it. > > I've got a solution or at least a sort of work-around for this. As of > svn 530, error-kit provides a 'rebind-fn' function You can pass it a > function definition and it will stuff the dynamic context needed by > error-kit (via lexicals) into the given fn and re-dynamically-bind > them there. This along with some other adjustments to how error-kit > communicates with itself across stack frames allows for this: > > (with-handler > (doall > (pmap (rebind-fn > #(if (< % 5) > % > (raise *error* "foo"))) > (range 10))) > (handle *error* [msg] > (str "caught " msg))) > > That returns "caught foo". > > The two key pieces there are the 'doall' and 'rebind-fn'. > > Leaving out both the 'doall' and 'rebind-fn' would mean that pmap may > not raise the error until after leaving the dynamic scope of the > with-handler. The 'raise' would not see the with-handler, and throw a > normal Java Exception, producing the same results as you'd get from > using try/catch in a similar way: > > java.lang.Exception: foo > > Including the 'doall' but leaving out 'rebind-fn' would still prevent > 'raise' from seeing that its inside a with-handler, and so would still > throw a normal Java Exception, which the with-handler would decline to > catch: > > java.lang.RuntimeException: java.util.concurrent.ExecutionException: > java.lang.Exception: foo (NO_SOURCE_FILE:0) > > Leaving out the 'doall' but including 'rebind-fn' produces the > strangest result. The 'rebind-fn' would allow 'raise' to see the > with-handler context, but which would no longer be in place when the > 'raise' actually executes. This allows error-kit's internal exception > object to sneak out into the light of day: > > Error Kit Control Exception: default, {:args ("caught foo"), :hfunc > #<user$eval__1897$fn__1901 user$eval__1897$fn__1...@1a791f>, :blockid > G__1899, :htag clojure.contrib.error-kit/*error*, :rfunc > #<core$identity__3483 clojure.core$identity__3...@c3e967>} > > Scary, right? So don't do that. > > If you correctly use 'rebind-fn' in contexts that are forced while > still within the appropriate with-handler context, you can use the > full power of error-kit, including continue, continue-with, > bind-continue, etc: > > (defn whine [] > (raise *error* "whine")) > > (with-handler > (doall > (pmap (rebind-fn > #(with-handler > (if (< % 5) % (whine)) > (bind-continue insert [x] x))) > (range 10))) > (handle *error* [msg] > (continue insert (str "caught " msg)))) > > If anyone is still reading and has a better idea for how to get > try/catch and dynamic binding contexts to stay in sync, I'm all ears. > > --Chouser > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---