of course I missed something :-(

2011/1/25 Laurent PETIT <laurent.pe...@gmail.com>:
> 2011/1/25 Ken Wesson <kwess...@gmail.com>:
>> On Mon, Jan 24, 2011 at 7:32 PM, Laurent PETIT <laurent.pe...@gmail.com> 
>> wrote:
>>> 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"))))
>>
>> 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. On the other hand, my
>> version's vector wrap is a bit icky, perhaps. :)
>>
>> Yours works if the binding vector is empty, too; I suppose that's a
>> good idea. You've also incorporated the core version's error reporting
>> code. If this makes it into core in any form it should probably
>> include those features. :)
>
> What about this version which gets rid of the double call to close ?
> Did I miss something (it's getting late here) ?
>
> (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
>                                (with-open ~(subvec bindings 2) ~@body)
>                                (catch Throwable t#
>                                        (try (. ~(bindings 0) close) (catch
> Throwable _)) ; eat close exception
>                                  (throw t#))) ; and rethrow body exception
>                              (. ~(bindings 0) close))
>    :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