-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Catching all exceptions: unexpected behavior #24
Comments
Initial thoughts: (catch Object o ...) is the try+ equivalent of (catch Exception e ...): "catch every thrown thing". Once inside the (catch Object o ...) handler you can decide how you want to act based the value or type of o.
|
I guess each of your points makes sense, I was just hit by an unfortunate combination here. I modified our code to (catch Object o ...) for now, which means I have to start making use of &throw-context. Formerly my code would do (.printStackTrace e) and (.getMessage e). I don't think this is wrong, but I still feel this is a trap for the unwary. I think at the very least it merits a mention in the slingshot README. My takeaway is: try+ is not "100% compatible with Clojure and Java's native try and throw both in source code and at runtime". Your (catch Exception) clauses will not catch all exceptions. They need to be modified to (catch Object o) and use &throw-context to get at the stacktrace. The twist here is that you will only run into problems when something down the call chain uses throw+ :-) |
try+ (catch Exception) clauses will catch all exceptions. They won't catch non-Throwable objects thrown by throw+. I agree that this warrants a section in the README. What you may want here is:
The Object clause will then catch only objects not derived from Exception. (this may have the unwanted effect of catching non-Exception Throwables. If that's a problem, another catch clause can fix it up. |
Just wandering in to note that I got bitten by this just now. Reading over the discussion I think I agree that it can't be any other way, but it is not at all intuitive - I imagined that (catch SomeClass x) was checking the class of the thrown exception, rather than whatever slingshot's idea of a throw-context is. So I guess I don't really agree with the statement that (catch Exception) will catch all exceptions - it catches everything that slingshot considers to be a thrown exception, but not what slingshot considers to be other thrown things; thinking instead at the JVM or Java level, there are things which are unarguably exceptions which are not being caught. Some clarification of this in the readme is probably all that is needed. |
Why not add a special syntax for catching anything? I propose (try+
(stuff)
(catch :anything _
(println "caught a thrown+ object or an Exception!"))
(catch :anything-throwable _
(println "caught a thrown+ object or something Throwable,
maybe even OutOfMemoryError! gross!"))) It's a lot less weird looking than I guess a symbol like Edit: Something to catch any thrown+ objects without catching Exceptions would also be nice, maybe: (try+
(stuff)
(catch :non-exceptions _
(println "caught a thrown+ object, but not an Exception!"))) |
sorry for the outrageously long delay. anyone who is still interested, please review: #46 |
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
While we're reworking this code, remove slingshot. It's easy to handle the ex-data directly, and then we don't have to keep slingshot's potentially surprising behaviors in mind, e.g. (try+ ... (catch Exception ex ...)) may not actually catch ex. cf. scgilardi/slingshot#24 scgilardi/slingshot#52
I'm not actually sure if this is an issue or a question, but it certainly was unexpected and caused problems in my existing software, so here goes:
We went through our code recently and modified most try/catch blocks to try+/catch, using additional functionality provided by slingshot. So far so good. Problem is, we often had a (catch Exception e...) clause at the end, that was supposed to catch pretty much everything that could happen in that block and perform cleanups.
Now, things were fine as long as exceptions were thrown by java code. But then it turned out that clj-http throws its unexpected-status exceptions (like "403 forbidden", see wrap-exceptions in client.clj in clj-http) using throw+. And what gets passed to throw+ is a response object (a map) and a string.
The result was that our code worked fine as long as the block around clj-http used (try/catch), but completely missed the exception when try was changed to try+, because slingshot would "unpack" the object that was thrown, find a map, and try to match that. And (catch Exception e...) would not match a map.
To demonstrate the problem:
(try (http-request {:url "http://fablo-data-production-eu-west-1.s3.amazonaws.com/no-permission" :method :get}) (catch Exception e (prn "got it" (.toString e))))
"got it" "slingshot.ExceptionInfo: clj-http: status 403"
-- this is fine and what I would expect.
(try+ (http-request {:url "http://fablo-data-production-eu-west-1.s3.amazonaws.com/no-permission" :method :get}) (catch Exception e (prn "got it" (.toString e))))
this does not get caught and SLIME catches the exception: clj-http: status 403 [Thrown class slingshot.ExceptionInfo], which I think is a problem.
There are actually several problems here.
As a temporary workaround I'll hunt down my try+ blocks and introduce (catch (constantly true)) or (catch Object), but I wanted to bring it up and see what you think.
The text was updated successfully, but these errors were encountered: