On Fri, Jul 29, 2011 at 2:48 AM, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> So they decided to go the route of adding a .getSuppressed() (Exceptions)
> method in Throwable, thus behaving differently from other finally clauses
> ...
>
> ... so now we have a (with-open) whose semantics are not aligned with those
> semantics of Java 7' try-with-resources statement, wrt exception shadowing
> from the "finally" block ... :-/

Easily fixed. We already wrap everything in RuntimeException, right?
And it's already been suggested elsewhere that we should probably use
a specialized subclass, say ClojureRuntimeException.

So, just implement ClojureRuntimeException, add some fields and
getShadowed and appendShadowed methods to this, and redefine with-open
so that it catches any exception, stuffs it into a
ClojureRuntimeException as the cause exception if it's not already a
ClojureRuntimeException, and now it's holding a
ClojureRuntimeException, closes open resources and appends any thrown
exceptions to the ClojureRuntimeException's shadowed list. Then throws
that. For one resource, something like this should be emitted:

(let [x the-resource]
  (try
    ... body that works with x ...
    (catch Throwable t
      (let [t (if (instance? ClojureRuntimeException t)
                t
                (ClojureRuntimeException. (.getMessage t) t))]
        (try
          (.close x)
          (catch Throwable tt (.appendShadowed t tt)))
        (throw t))))
  (.close x))

There's a couple of tiny leaks (.getMessage could throw something, and
(ClojureRuntimeException. ...) could throw OOME, plus the
infinitesimal chance of a random VMError cropping up) but it looks
solid enough for production use and gives Java 7ish semantics.

The exception wrapping code elsewhere can do something similar in
terms of wrapping in ClojureRuntimeException and only if it's not
already wrapped. It'd be nice to be able to differentiate wrapped
exceptions from "natural" RuntimeExceptions, and not to have the same
one get rewrapped umpteen times so that you have a cause chain of half
a dozen RuntimeExceptions before the cause exception.

Then we can also have

(defn unwrap [x]
  (if (instance? ClojureRuntimeException x)
    (recur (.getCause x))
    x))

and it will unwrap all Clojure's wrapping, and stop right there even
if the exception originally caught and wrapped inside Clojure already
had a cause exception.

-- 
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.

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