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

Reply via email to