On Jun 6, 2009, at 3:39 PM, Chouser wrote:
On Sat, Jun 6, 2009 at 10:42 AM, Stephen C. Gilardi<squee...@mac.com> wrote:I've checked in changes to clojure.contrib.except to allow the functions it provides to produce exceptions that wrap other exceptions: they now support"causes".I believe it's now fully general and will be convenient to use for all ofour exceptional needs.The attached text file contains a demo session at the repl showing some ofits features.This looks really easy to use, Stephen, thanks.
Thanks!
Since the time I put the rather more top-heavy error-kit in contrib, it's become increasingly clear to me that hardly anybody (myself included) need or use the continue-with and bind-continue features it provides. That leaves as its only used feature the ability to define and catch custom error types that can be created without AOT compilation. But I'm starting to come around to what I think Rich has been pointing out all along: that having singly-typed errors is not necessarily a great idea. Clojure multi-methods don't require objects to have a single type after all -- you can dispatch on whatever you'd like. Why should exceptions be any different?
That's interesting. I'm sorry I hadn't yet looked at error-kit in detail. I do like the idea of using more idiomatic Clojure techniques for communicating error information up the stack.
So here's an idea: what if Clojure (or contrib for now) provided a single new Exception type that besides the normal error string also carried an object: probably a map with unspecified content (a bit like metadata is now). Then a lib like contrib.except could make it easy to toss bits of detail into the exception that could be read easily when caught. This would allow the simplicity that contrib.except provides now and would allow you to provide as much detail as an error-kit error without even having to declare an error type.
That's cool. You mentioned metadata. Perhaps that would be a good way to implement it. As a prototype to play with, I've enclosed Condition.java which for now is convenient to place in clojure/src/jvm/ clojure/lang . It's a subclass of Throwable which is (mostly and when it's done completely) immutable and supports metadata. I've also enclosed a version of except.clj that include "handler-case" and "raise" macros That use it to communicate a map from the site of an error to a handler for the error.
I used Common Lispy names for the functions, but we may or may not want to keep that given that there are differences in the operations.
Perhaps using it would look something like: (defn foo [x y] (if (neg? x) (throwf :source ::Args, :arg 'x, :value x, "The value x may not be negative") (+ x y))) (try (foo -5 10) (catch ClojureError e (if-not (isa? ::Args (:source e)) (throw e) (printf "Argument was incorrect:" e)))) I suppose the catch clause could be augmented: (tryf (foo -5 10) (catchf [e] (isa? ::Args (:source e)) (printf "Argument was incorrect:" e)))
Here's how it looks with this handler-case and raise: user=> (defn foo [x y] (if (neg? x)(raise :source ::Args :arg 'x :value x :message "shouldn't be negative")
(+ x y))) #'user/foo user=> (foo 3 4) 7 user=> (handler-case :source c (foo -5 10) (handle ::Args (printf "Argument was incorrect: %s\n" ^c)))Argument was incorrect: {:arg x, :message "shouldn't be negative", :source :user/Args, :value -5}
nil c also contains the stack trace accessible by (.getStackTrace c).
Any thoughts?
Could be cool. Back at ya. :) --Steve
Condition.java
Description: Binary data
except.clj
Description: Binary data
smime.p7s
Description: S/MIME cryptographic signature