Today’s fashionable programming languages, in particular Ruby, Python, and Erlang, have something in common: really lousy error messages. I guess we just gotta suck it up and deal with it. But today I got something really, uh, special from Erlang.
Doing loops with tail recursion is wonderful, except when it’s not.
2> seq:scan('o10.ap').
=ERROR REPORT==== 19-Sep-2007::23:35:10 ===
Error in process <0.31.0> with exit value: {badarg,[{erlang,tl,[{concat,
{concat,{concat,{concat,{concat,{concat,{concat,{concat,{concat,{concat,
{concat,{concat,{concat,{concat,{concat,{concat,{concat,{concat,{concat,
{concat,{concat,{concat,{concat...
** exited: {badarg,
[{erlang,
tl,
[{concat,
{concat,
{concat,
{concat,
{concat,
{concat,
{concat,
{concat,
{concat,
{concat,{concat,{...},...},{char_class,...}},
47},
{char_class,[{48,57}]}},
{char_class,[{48,57}]}},
47},
{char_class,[{48,57}]}},
{char_class,[{48,57}]}},
47},
{pclosure,{comp_class,". "}}},
32}]},
{regexp,first_match,3},
{regexp,match,5},
{regexp,match,2},
{seq,scan_line,3},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_loop,3}]} **
The error happened in line 3 of scan_line
, which has nothing
to do with the line number in the source file. Sigh.
Comment feed for ongoing:
From: Simon Willison (Sep 20 2007, at 12:38)
Just out of interest, what do you dislike about Python's error messages? I've always found them really helpful.
[link]
From: John Minnihan (Sep 20 2007, at 12:45)
At least it's an interesting pattern... squint at it for a few minutes. You'll soon find yourself caring nothing at all about the error & simply wanting a beer.
[link]
From: Peter Schow (Sep 20 2007, at 13:00)
You'd think that Erlang, designed twenty years ago, at the end of the Pascal era would have better error diagnostics.
[link]
From: Tor Norbye (Sep 20 2007, at 14:07)
This is another area IDEs can hopefully help a bit. If you run into anything similar in Ruby, please let me know! I'm trying to add some diagnostics around common error messages - especially those that are fixable - see http://blogs.sun.com/tor/entry/ruby_screenshot_of_the_week17
[link]
From: Thomas Lindgren (Sep 20 2007, at 14:15)
So, your error was in seq:scan_line/3?
The exception value shown is just a term, see erlang:exit/1 and erlang:error/1.
NB: I agree that the errors do leave something to be desired. For example, module, line number, value(s) causing the exception, detailed call stack, ...
[link]
From: Patrick Logan (Sep 20 2007, at 14:35)
Yeah, well, apparently you haven't tried Haskell yet. :-)
I agree erlang's messages are, em, not always the best. After using it a bit, there are just a few that occur frequently for me, and for any of those I know pretty well what to look for.
Obscure cases do come up. In this case, it looks like some function is not defined with precise enough patterns.
seq:scan should probably not be defined for atoms (symbols). Single quotes define an atom, and so 'foo' is the same as foo, but "foo" is a list...
[$f | [$o | [$o | []]]].
is_list("foo").
true
is_list('foo').
false
So the author of seq:scan should probably have included a guard to only accept lists...
scan(Arg) when is_list(Arg) ->
...
This error will be a bit more understandable, a "clause" error as the function would have no clause for terms.
"badarg" may be a reasonable error for the one that was actually thrown in your example, but unfortunately it occurred deep into some recursion that was not helpful. Being aggressive with patterns and guards will result in errors closer to the programmer.
[link]
From: Matt Chaput (Sep 20 2007, at 14:40)
Best fake e.e.cummings poem ever.
Python has lots of error messages that are misleading or poorly worded. Like "Argument supplied twice." That means you changed the signature of a function, but forgot to update a call somewhere, so now one of the one of the values you supplied is now captured as a positional argument, but you're still supplying the same argument as a keyword. Or something, I forget the exact details. But it took me a couple hours to figure out what Python was trying to tell me.
But anyone who's skimmed the dragon book can tell you that supplying meaningful error messages is probably the hardest thing in language design. You really have to design it deep into the implementation for it to be useful.
Hardcore programmers like to make fun of Java for its ubibquity, like being used by DeVry students makes the language tainted. But one of the consequences of it being ubiquitous is it seems like Sun invested a ton of money in documentation and error messages. Java probably has the best error messages of any programming language.
[link]
From: Bob Aman (Sep 20 2007, at 15:12)
I remember getting STL errors that looked like that back when I was forced to write C++ in college. And I've definitely gotten 400+ line exceptions from Java applications before. I don't think I've ever seen anything as bad as any of those in either Ruby or Python. That's not to say Ruby or Python are innocent, but it's not a problem of too much information. Quite the opposite.
[link]
From: Cedric Beust (Sep 20 2007, at 20:13)
I recently wrote about Erlang here:
http://beust.com/weblog/archives/000461.html
and indeed, its abysmal error handling was a very sore point for me. Overall, the language feels very old and I really question the sanity of people who see Erlang as the Next Big Thing...
Interesting language nevertheless.
--
Cedric
[link]
From: Wilson Bilkovich (Sep 20 2007, at 22:06)
I agree, which is why Rubinius now has awesome colorized backtraces:
http://supremetyrant.com/ruby/backtraces.png
I guess we should add a few dozen "concat"s to that for Erlang compatibility.
[link]
From: breath (Sep 20 2007, at 22:58)
>Overall, the language feels very old and I really question the sanity of people who see Erlang as the Next Big Thing...
I'm pretty sure people who are into Erlang think it's about the runtime rather than the language.
[link]
From: Paul W Homer (Sep 21 2007, at 13:25)
It was so refreshing 10 years ago when I switch to Java from C. The error messages we so good and so relevant that they almost annoyed me.
What goes around, comes back again. For really "great" error handling try GWT. Java converted to Javascript then run on a browser just to add some extra spice.
Why shouldn't it be simple?
[link]
From: Sam Penrose (Sep 21 2007, at 13:39)
I've often thought that Python and other interpreted languages should have a mode which, at a minimum, prints the offending object and its local name. E.g.:
>>> x = None # imagine this is some object you'd never expect to be None
>>> for i in x: pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: iteration over non-sequence
I don't understand why this doesn't read "iteration over non-sequence 'x'". I assume the reason it doesn't read "iteration over non-sequence 'None' bound to name 'x'" is that casting an arbitrary Python object to string may be Bad, but surely you could split the difference by printing the object's type. How much collective programmer time has been spent determining that:
TypeError: iteration over non-sequence
meant
TypeError: iteration over non-sequence 'x' of type 'NoneType'?
I bet the answer is measurable in person-years ...
[link]
From: amk (Sep 26 2007, at 10:25)
Sam Penrose: that error message is improved in Python 2.5; you get "TypeError: 'NoneType' object is not iterable".
[link]
From: Edward Ocampo-Gooding (Sep 29 2007, at 08:38)
The part that I remember most about my short stint with programming C# (with Mono) were its error messages; I've never seen such helpful and clear messages before, especially not those that come with generic examples of what my error probably was and how to fix them. Man, that was cool.
[link]