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

Reply via email to