On Tue, Aug 2, 2011 at 3:11 AM, recurve7 <dan.m...@gmail.com> wrote: > Here's one example where recursion and lack of positional error > feedback make it hard for me, as someone coming from Java, to spot the > error (and seeing "ClassCastException" threw me off and had me > wondering where/how I had done something like that): > > user=> (defn fac [n] (if (= n 1) 1 (* n fac (- n 1)))) > #'user/fac > user=> (fac 3) > java.lang.ClassCastException: user$fac cannot be cast to > java.lang.Number (NO_SOURCE_FILE:0)
This is saying that a "user$fac" was found where a number was expected. You have a function called fac in the user namespace -- this is "user$fac" to Java. So, you probably tried to perform arithmetic on a function. It's a math function, so you probably meant to call it and perform arithmetic on the result, and left out a pair of parentheses. It is true that the messages commonly encountered could stand to be better documented on a Clojure site. I'm wondering if we could go further, though, and make REPL exception printing more informative. The Java exception gets stored in *e, so someone can always type *e to retrieve it, or (.printStackTrace *e), etc., so printing an interpretation of the exception wouldn't render the raw exception inaccessible. This suggests trying to parse common exceptions into Clojurish messages; e.g. the above could be found to be a CCE, then the detail message parsed to extract the classnames; then a message pieced together based on those, e.g. java.lang.Number -> a number clojure.lang.Cons/LazySeq/PersistentList/etc. -> a list or seq clojure.lang.Vector -> a vector w.x$y when a function w.x/y exists -> the function w.x/y ... and the shallowest Clojure function before interop can be dug out of the stack trace, in the above case clojure.core/*, and the above message could then come out as Error: expected a number for *, but found the function user/fac instead. In the case it's a function in the wrong place, the addendum could be generated: (Perhaps you meant to call the function, but left out a pair of parentheses.) The lack of line number information for errors in REPL evaluations is also an issue. I suggest that when a defn is evaluated at the REPL, it gets metadata like {:file REPL$user$fac :line 1} where the line number counts from the "defn" on down. The message printer can parse the file name from the exception and if it's REPL$anything parse it as referring to a REPL evaluation and not an actual file, printing something like "line 1 of user/fac" in the OP's instance. IDEs can also possibly have go-to-error pull up the relevant line in the REPL backbuffer, searching backwards for the most recent evaluation of (defn fac ...) in user for instance and then finding line 1 of that. When the error's in a normal source file, of course, existing behavior is adequate for the most part (though there are sometimes problems when macros are involved -- particularly, the line number is commonly the start of the macro body, though not oddly when that macro is "defn"). Clooj would be a good place to experiment with a friendlier REPL error reporting system. -- 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