I'm trying to understand what is going on with a program where I've got exceptions "disappearing" without any notice (and a thread stops working).
The simplest case I could come up with to reproduce the issue is this:
(defn -main []
(let [a (future (do (println "Ouch... ")
(/ 0 0)
(println "We never arrive here")))]
(Thread/sleep 1000)
(println "Hmmmm" #a)))
Surely enough, when run at the repl (or using lein run), I get an exception:
so.core> (-main)
Ouch...
ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:156)
Which is the behavior I expected.
However now if I remove the dereferencing of the future:
(defn -main []
(let [a (future (do (println "Ouch... ")
(/ 0 0)
(println "We never arrive here")))]
(Thread/sleep 1000)
(println "Hmmmm")))
Here's the output:
so.core> (-main)
Ouch...
Hmmmm
nil
so.core>
So the future is executed (otherwise "Ouch..." wouldn't be print) and obviously an exception is then thrown (otherwise "We never arrive here" would print)... But that exception is nowhere to be found and the program continues as if everything was fine.
Apparently as long as I don't try to dereference the future, the thread can silently die, in the middle of its work (in this case printing to stdout), and the exception is nowhere to be found.
Is this normal?
Am I supposed to find a (stack)trace of that exception in one of my Emacs / cider buffers?
What would be an idiomatic way to have a future doing its work (e.g. consuming messages from a queue) and yet "warn" me when something goes wrong?
Should I wrap every future call inside try/catch blocks?
Should I set a default uncaught exception handler?
Am I not supposed to run a "non-stopping" thread using a future?
Basically I'm very confused by the behaviour of Java / Clojure here and would like to have both explanation as to why it's behaving that way and how I'm supposed to deal with this issue.
In clojure future is a macro that produces a reified java.util.concurrent.Future, and dereferencing it calls the Future.get method. That method can throw an ExecutionException which represents an uncaught exception in the thread. So if you don't dereference you don't call .get and you don't get the exception.
The clojure doc site has the source, so you can see the actual implementation here.
If you don't want to dereference I suppose you should try/catch in the thread, and handle in whatever way you choose.
Related
As indicated by Tom Browder in this issue, the $*ARGFILES dynamic variable might contain invalid filehandles if any of the files mentioned in the command line is not present.
for $*ARGFILES.handles -> $fh {
say $fh;
}
will fail with and X::AdHoc exception (this should probably be improved too):
Failed to open file /home/jmerelo/Code/perl6/my-perl6-examples/args/no-file: No such file or directory
The problem will occur as soon as the invalid filehandle is used for anything. Would there be a way of checking if the filehandle is valid before incurring in an exception?
You can check if something is a Failure by checking for truthiness or definedness without the Failure throwing:
for $*ARGFILES.handles -> $fh {
say $fh if $fh; # check truthiness
.say with $fh; # check definedness + topicalization
}
If you still want to throw the Exception that the Failure encompasses, then you can just .throw it.
TL;DR I thought Liz had it nailed but it seems like there's a bug or perhaps Ugh.
A bug?
It looks like whenever the IO::CatHandle class's .handles method reaches a handle that ought by rights produce a Failure (delaying any exception throw) it instead immediately throws an exception (perhaps the very one that would work if it were just delayed or perhaps something broken).
This seems either wrong or very wrong.
Ugh
See the exchange between Zoffix and Brad Gilbert and Zoffix's answer to the question How should I handle Perl 6 $*ARGFILES that can't be read by lines()?
Also:
https://github.com/rakudo/rakudo/issues/1313
https://github.com/rakudo/rakudo/search?q=argfiles&type=Issues
https://github.com/rakudo/rakudo/search?q=cathandle&type=Issues
A potential workaround is currently another bug?
In discussing "Implement handler for failed open on IO::CatHandle" Zoffix++ closed it with this code as a solution:
.say for ($*ARGFILES but role {
method next-handle {
loop {try return self.IO::CatHandle::next-handle}
}
})
I see that tbrowder has reopened this issue as part of the related issue this SO is about saying:
If this works, it would at least be a usable example for the $*ARGFILES var in the docs.
But when I run it in 6.d (and see similar results for a 6.c), with or without valid input, I get:
say not yet implemented
(similar if I .put or whatever).
This is nuts and suggests something gutsy is getting messed up.
I've searched rt and gh/rakudo issues for "not yet implemented" and see no relevant matches.
Another workaround?
Zoffix clearly intended their code as a permanent solution, not merely a workaround. But it unfortunately doesn't seem to work at all for now.
The best I've come up with so far:
try {$*ARGFILES} andthen say $_ # $_ is a defined ArgFiles instance
orelse say $!; # $! is an error encountered inside the `try`
Perhaps this works as a black-and-white it either all works or none of it does solution. (Though I'm not convinced it's even that.)
What the doc has to say about $*ARGFILES
$*ARGFILES says it is an instance of
IO::ArgFiles which is doc'd as a class which
exists for backwards compatibility reasons and provides no methods.
And
All the functionality is inherited from
IO::CatHandle which is subtitled as
Use multiple IO handles as if they were one
and doc'd as a class that is
IO::Handle which is subtitled as
Opened file or stream
and doc'd as a class that doesn't inherit from any other class (so defaults to inheriting from Any) or do any role.
So, $*ARGFILES is (exactly functionally the same as) a IO::CatHandle object which is (a superset of the functionality of) an IO::Handle object, specifically:
The IO::CatHandle class provides a means to create an IO::Handle that seamlessly gathers input from multiple IO::Handle and IO::Pipe sources. All of IO::Handle's methods are implemented, and while attempt to use write methods will (currently) throw an exception, an IO::CatHandle is usable anywhere a read-only IO::Handle can be used.
Exploring the code for IO::CatHandle
(To be filled in later?)
In Lablgtk, whenever there is an exception in a callback, the exception is automatically caught and an error message is printed in the console, such as:
(prog:12345) LablGTK-CRITICAL **: gtk_tree_model_foreach_func:
callback raised an exception
This gives no stack trace and no details about the exception, and because it is caught I cannot retrieve this information myself.
Can I enable more detailed logging information for this case? Or prevent the exception from being caught automatically?
I guess the best way to do so is to catch your exception manually and handle it yourself.
let callback_print_exn f () =
try f () with
e -> my_exn_printer e
Assuming val my_exn_printer : exn -> unit is your custom exception printer, you can simply print your callbacks exceptions by replacing ~callback:f by ~callback:(callback_print_exn f) in your code.
Of course, you can also with that method send that exception to another
thread, register a "callback id" that would be passed along with your exception...
About the stack trace, I'm not sure you can retrieve it easily. As it's launched as a callback, you probably want to know the signal used and that can be stored in your callback handler.
I had another similar issue, but this time it was harder to find where to put the calls to intercept the exception.
Fortunately, this time there was a very specific error message coming from the Glib C code:
GLib-CRITICAL **: Source ID ... was not found when attempting to remove it`
Stack Overflow + grep led me to the actual C function, but I could not find which of the several Lablgtk functions bound to this code was the culprit.
So I downloaded the Glib source, added an explicit segmentation fault to the code, compiled it and used LD_LIBRARY_PATH to force my modified Glib version to be loaded.
Then I ran the OCaml binary with gdb, and I got my stack trace, with the precise line number where the Lablgtk function was being called. And from there it was a quick 3-line patch.
Hacks like this one (which was still faster than trying to find where to intercept the call) could be avoided by having a "strict mode" preventing exceptions from being automatically caught. I still believe such a switch should be available for Lablgtk users, and hope it will eventually be available.
I've just been scratching my hairs for a long time with an error I couldn't find. It turned out to be an arity exception but apparently because it happened on the EDT I couldn't "see" it. It didn't show in the "lein run" terminal when run from a terminal and it didn't show in any Emacs buffer when run from Emacs.
After a very long time I ended up doing this:
(try (function-call-with-arity-error ...) (catch Exception e (println e)
and, at last, thanks to this, I got to see this printed:
#<ArityException clojure.lang.ArityException: wrong number of args passed to...
and hence I've been able to find my error.
And if I do this:
(do
(println "trying...")
(arity-error-here-on-purpose) ; this ones throws the arity error
(println "done")
)
Then the terminal prints "trying..." but never gets to "done...".
I tried setting a default uncaught exception handler: the exception isn't getting caught. It's as if the program or the EDT was "stuck" after the arity exception (without printing anything anywhere).
How am I suppose to deal with this the next time? Because I couldn't see any message anywhere it took me a really long time to find. Once again: nothing in the 'lein run' terminal and nothing in any Emacs buffer.
Should I create a function that wraps calls that should happen on the EDT inside try / catch manually and that then logs/println the exception?
Also note that this is in a relatively "long" Clojure app: 1000 lines of code, so I can't paste it here and I couldn't reproduce that behavior in a short example (but it happens consistently in my app).
You can register an uncaught exception handler with a Thread so you don't have to wrap all the calls that can occur on the EDT.
Thread.UncaughtExceptionHandler
Try registering one with the EDT and seeing if this gives you the desired behavior.
In my ClojureScript programs running in FireFox 5.0 on Ubuntu 10.04.1 LTS, I get a single cryptic line when an exception is thrown.
'Error: No protocol method ISeqable.-seq defined for type object: [object Object]' when calling method: [nsIDOMEventListener::handleEvent]
The "-seq" bit seems strange to me and I have searched the generated javascript files for it and not found it.
I hope I am not missing something entirely obvious, but how do I get a stack trace of the exception thrown? How are you debugging your scripts?
Unfortunately stack traces from errors rely on browser support. Most (all?) browsers will allow you to access a canned version of the stack trace (usually the top 10 elements, iirc) as a string by dereferencing the 'stack' field, so you could do something like this:
(try ...throws...
(catch js/Error e
(.log js/console (.-stack e))))
However, string stack traces aren't much fun, you can't click them to take you to the source. Better is printing the exception directory to the javascript console (if it's available) to print stack traces with clickable links. E.g.
(try ...throws...
(catch js/Error e
(.log js/console e)))
At least in chrome, this only works if the javascript console was open when the error was thrown. This is great for debugging, but less useful when the error was unexpected.
The javascript console objects provided by most browsers have lots of useful functions that you can use from clojurescript. If you want to get helpful line numbers though, you probably want to write a couple of macros to inject the code to print to the console, otherwise all your line numbers will point to your print function.
Looks like you are passing a Javascript object to a Clojurescript function which expects a Clojure sequence. Try (my-function (js->clj my-thing)) edit: or, I'm guessing you're using (.strobj) where you don't need to
I've been trying to create a user-defined exception in Clojure, and have been having all sorts of problems. I tried the method outlined here:
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#User-Defined_Exceptions
(gen-and-load-class 'user.MyException :extends Exception)
But that doesn't seem to work in Clojure 1.2 (or I'm doing something wrong...). My environment is Clojure 1.2, Emacs, and lein swank.
Thanks for your help!
Rather than generating custom classes, there are two much simpler ways to use custom exceptions:
Use slingshot - this provides custom throw+ and catch+ macros that let you throw and catch any object, as well as exceptions.
In clojure 1.4 and above, you can use clojure.core/ex-info and clojure.core/ex-data to generate and catch a clojure.lang.ExceptionInfo class, which wraps a message and a map of data.
Using this is straightforward:
(throw (ex-info "My hovercraft is full of eels"
{:type :python-exception, :cause :eels}))
(try (...)
(catch clojure.lang.ExceptionInfo e
(if (= :eels (-> e ex-data :cause))
(println "beware the shrieking eels!")
(println "???"))))
Or in a midje test:
(fact "should throw some eels"
(...)
=> (throws clojure.lang.ExceptionInfo
#(= :eels (-> % ex-data :cause))))
Make a file src/user/MyException.clj (where src is on CLASSPATH) containing:
(ns user.MyException
(:gen-class :extends java.lang.Exception))
Check the value of *compile-path* at the REPL. Make sure this directory exists and is on CLASSPATH. Create the directory if it doesn't exist; Clojure won't do so for you.
user> *compile-path*
"/home/user/foo/target/classes/"
user> (System/getProperty "java.class.path")
".......:/home/user/foo/target/classes/:......."
Compile your class:
user> (compile 'user.MyException)
user.MyException
If it worked, in *compile-path* you should now have files something like this:
/home/user/foo/target/
/home/user/foo/target/classes
/home/user/foo/target/classes/user
/home/user/foo/target/classes/user/MyException.class
/home/user/foo/target/classes/user/MyException__init.class
/home/user/foo/target/classes/user/MyException$loading__4410__auto__.class
Restart your Clojure REPL / JVM to load these classes. Again, make sure these new class files are on CLASSPATH. Now you should be able to use your class:
user> (user.MyException.)
#<MyException user.MyException>
FWIW, unless you are creating a custom exception for interop reasons you may want to consider using clojure.contrib.condition instead. It comes with a precompiled custom exception that you piggy-back custom data onto using it's API. I've been able to avoid creating many custom exceptions by using it instead. The docs are here:
http://clojure.github.com/clojure-contrib/condition-api.html