> My usual experience with Clojure has been that the stack traces are long... but the exception error messages are generally pretty good, and the stack frames that correspond to user code generally have good information on the position of the offending statement.
I do not agree, but please note my comment isn't talking about "running" stack traces here it's talking about the compiler blowing up on what is essentially a syntax error:
(let [{:keys foo} {:foo 1}]
(print foo))
note how `foo` is bare rather than in a vector. Put that in a script, `clj -m` it
Exception in thread "main" java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling:(hello.clj:5:3)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6567)
at clojure.lang.Compiler.analyze(Compiler.java:6361)
at clojure.lang.Compiler.analyze(Compiler.java:6322)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5708)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5139)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3751)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6558)
at clojure.lang.Compiler.analyze(Compiler.java:6361)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6548)
at clojure.lang.Compiler.analyze(Compiler.java:6361)
at clojure.lang.Compiler.access$100(Compiler.java:37)
at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:529)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6560)
at clojure.lang.Compiler.analyze(Compiler.java:6361)
at clojure.lang.Compiler.analyze(Compiler.java:6322)
at clojure.lang.Compiler.eval(Compiler.java:6623)
at clojure.lang.Compiler.load(Compiler.java:7064)
at clojure.lang.RT.loadResourceScript(RT.java:370)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.load(RT.java:440)
at clojure.lang.RT.load(RT.java:411)
at clojure.core$load$fn__5018.invoke(core.clj:5530)
at clojure.core$load.doInvoke(core.clj:5529)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5336)
at clojure.core$load_lib$fn__4967.invoke(core.clj:5375)
at clojure.core$load_lib.doInvoke(core.clj:5374)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5413)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$require.doInvoke(core.clj:5496)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.main$main_opt.invoke(main.clj:335)
at clojure.main$main.doInvoke(main.clj:440)
at clojure.lang.RestFn.invoke(RestFn.java:436)
at clojure.lang.Var.invoke(Var.java:423)
at clojure.lang.AFn.applyToHelper(AFn.java:167)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
at clojure.lang.RT.seqFrom(RT.java:505)
at clojure.lang.RT.seq(RT.java:486)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$reduce1.invoke(core.clj:890)
at clojure.core$destructure$pb__4541$pmap__4544$fn__4547.invoke(core.clj:4013)
at clojure.core$reduce1.invoke(core.clj:896)
at clojure.core$destructure$pb__4541$pmap__4544.invoke(core.clj:4014)
at clojure.core$destructure$pb__4541.invoke(core.clj:4028)
at clojure.core$destructure$process_entry__4557.invoke(core.clj:4030)
at clojure.core$reduce1.invoke(core.clj:896)
at clojure.core$destructure.invoke(core.clj:4033)
at clojure.core$let.doInvoke(core.clj:4046)
at clojure.lang.RestFn.invoke(RestFn.java:467)
at clojure.lang.Var.invoke(Var.java:427)
at clojure.lang.AFn.applyToHelper(AFn.java:172)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.lang.Compiler.macroexpand1(Compiler.java:6468)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6546)
... 40 more
Yeah… the third time around you might instantly know what it is, the first time around when it's a few levels down a type method not so much.
The first line of the error message tells you where and what the error is, almost exactly:
... Don't know how to create ISeq from: clojure.lang.Symbol, compiling:(hello.clj:5:3)
It's true that the full interpretation of the error message requires some experience with the language (ISeq? Symbol?), but when is that not the case? Consider this one character typo in a Java file:
voidx displayMessage(String message);
javac produces an error message that's just about as opaque as what Clojure produces in your example.
[ERROR] ... MessageSink.java:[5,4] error: cannot find symbol
Conversely, if I leave an open brace in Java source, I get the following kind of error from javac:
[ERROR] ... ConsoleMessageSink.java:[12,1] error: reached end of file while parsing
If I leave an open form in Clojure, it at least tells me the location of the form I left open:
Exception in thread "main" java.lang.RuntimeException: EOF while reading, starting at line 18, compiling:(toto/data.clj:255:1)
(Of course, thanks to paredit-mode, I had to play a minor trick on my editor to get it to let me even introduce that error in the first place.)
I do not agree, but please note my comment isn't talking about "running" stack traces here it's talking about the compiler blowing up on what is essentially a syntax error:
note how `foo` is bare rather than in a vector. Put that in a script, `clj -m` it Yeah… the third time around you might instantly know what it is, the first time around when it's a few levels down a type method not so much.