2011/1/25 Ken Wesson <kwess...@gmail.com>:
> Are we generally agreed that we want to preserve the body exception,
> if any, else the close exception, if any, else the body return value?
>
> Then, without further ado:
>
> (defmacro with-open2 [binding-exprs & body]
>  (if (> (count binding-exprs) 2)
>    `(with-open2 ~(vec (take 2 binding-exprs))
>       (with-open2 ~(vec (drop 2 binding-exprs))
>         ~@body))
>    (let [[sym expr] binding-exprs]
>      `(let [~sym ~expr
>             res# (try
>                    [(do ~@body)]
>                    (catch Throwable t# t#))]
>         (if (vector? res#) ; body didn't throw
>           (do
>             (.close ~sym) ; so let close throw
>             (res# 0))
>           (do ; body threw
>             (try (.close ~sym) (catch Throwable _#)) ; eat close exception
>             (throw res#))))))) ; and rethrow body exception
>
> user=> (with-open [x (Foo.)] (doit x))
> #<CompilerException java.lang.Exception: close exception (NO_SOURCE_FILE:242)>
> user=> (with-open2 [x (Foo.)] (doit x))
> #<CompilerException java.lang.Exception: doit exception (NO_SOURCE_FILE:40)>

What about starting from the current definition of with-open in
clojure.core, improving upon it (and at the same time, not building
intermediate wrapper vector) :

(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)
                              (try
                                (let [res# (with-open ~(subvec
bindings 2) ~@body)]
                                  ;body didn't throw
                                  (. ~(bindings 0) close)
                                  res#)
                                (catch Throwable t#
                                        (try (. ~(bindings 0) close) (catch
Throwable _)) ; eat close exception
                                  (throw t#)))) ; and rethrow body exception
    :else (throw (IllegalArgumentException.
                   "with-open only allows Symbols in bindings"))))

-- 
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