The changed code should catch 'Exception', not 'Throwable' because the latter is a common ancestor of both 'Exception' and 'Error'. An 'Error' must not be swallowed at any point in the system, unless you are writing an app server or a JVM implementation. ;-)
Regards, Shantanu On Jan 25, 6:11 am, Ken Wesson <kwess...@gmail.com> wrote: > On Mon, Jan 24, 2011 at 7:43 PM, Laurent PETIT <laurent.pe...@gmail.com> > wrote: > > 2011/1/25 Ken Wesson <kwess...@gmail.com>: > >> Ah, I guess it may be a bit cleaner to just eschew "finally" > >> altogether and close in the try and in the catch. The one thing that's > >> a bit icky about that is that if the body close throws, the catch > >> clause tries to close the stream again. > > > argh yes, this may be a problem ... > > There's also a bug: _ instead of _# in the close exception discarder. :) > > How's about: > > (in-ns 'clojure.core) > (defmacro with-open > "bindings => [name init ...] > > Evaluates body in a try expression with names bound to the values > of the inits, and a finally clause that calls (.close name) on each > name in reverse order." > {:added "1.0"} > [bindings & body] > (assert-args with-open > (vector? bindings) "a vector for its binding" > (even? (count bindings)) "an even number of forms in binding vector") > (cond > (= (count bindings) 0) `(do ~@body) > (symbol? (bindings 0)) `(let ~(subvec bindings 0 2) > (let [res# (try > (with-open ~(subvec > bindings 2) ~@body) > (catch Throwable t# > (try > (. ~(bindings 0) close) > (catch Throwable _#)) > (throw t#)))] > (. ~(bindings 0) close) > res#)) > :else (throw (IllegalArgumentException. > "with-open only allows Symbols in bindings")))) > > No double-closing and no vector. If the body throws, the exception is > caught, the close is done with any close exception suppressed, and the > original exception rethrown and that's it. If the body doesn't throw, > we store it in res and then close. If the close throws here, the > exception is allowed to propagate. Otherwise we return res. > > I've tested this with Foo and it works; modifying Foo to replace the > close throw with (println "closed"), the doit throw with the integer > literal 42, or both, I get: > > Both throw: > #<CompilerException java.lang.Exception: doit exception (NO_SOURCE_FILE:46)> > > Close throws: > #<CompilerException java.lang.Exception: close exception (NO_SOURCE_FILE:48)> > > Doit throws: > closed > #<CompilerException java.lang.Exception: doit exception (NO_SOURCE_FILE:46)> > > Neither throws: > closed > 42 > > The right exception escapes if any exceptions are thrown, and "closed" > is printed exactly once if close doesn't throw. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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