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