Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
Currently (1.10.0-RC5) stacktraces look like this:


user=> (Exception.)
#error {
 :cause nil
 :via
 [{:type java.lang.Exception
   :message nil
   :at [user$eval3 invokeStatic "NO_SOURCE_FILE" 1]}]
 :trace
 [[user$eval3 invokeStatic "NO_SOURCE_FILE" 1]
  [user$eval3 invoke "NO_SOURCE_FILE" 1]
  [clojure.lang.Compiler eval "Compiler.java" 7176]
  [clojure.lang.Compiler eval "Compiler.java" 7131]
  [clojure.core$eval invokeStatic "core.clj" 3214]
  [clojure.core$eval invoke "core.clj" 3210]
  [clojure.main$repl$read_eval_print__9068$fn__9071 invoke "main.clj" 414]
  [clojure.main$repl$read_eval_print__9068 invoke "main.clj" 414]
  [clojure.main$repl$fn__9077 invoke "main.clj" 435]
  [clojure.main$repl invokeStatic "main.clj" 435]
  [clojure.main$repl_opt invokeStatic "main.clj" 499]
  [clojure.main$main invokeStatic "main.clj" 598]
  [clojure.main$main doInvoke "main.clj" 561]
  [clojure.lang.RestFn invoke "RestFn.java" 397]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.RestFn applyTo "RestFn.java" 132]
  [clojure.lang.Var applyTo "Var.java" 705]
  [clojure.main main "main.java" 37]]}


Those are java stacktraces, even for code running inside Clojure. I believe many developers would benefit from stacktraces elements originated from Clojure being rendered in Clojure-aware way. For example:


  [clojure.core/eval "core.clj" 3214]
  [clojure.main/repl/read-eval-print "main.clj" 414]
  [clojure.main/repl "main.clj" 435]
  [clojure.main/repl-opt "main.clj" 499]
  [clojure.main/main "main.clj" 598]
  [clojure.main/main "main.clj" 561]


Key differences:

- Names demunged (user sees names as they appear in Clojure file, not how they got compiled to Java code. Not every Clojure user need to be aware of that part, I believe)
- Duplicate invoke/invokeStatic/doInvoke collapsed (again, this is an implementation detail, from Clojure user calling a method is a single operation. As a result, many stacktraces might become quite shorter)

I believe there are many more implementation details like protocol calls, multimethod calls, anonymous functions, where compilation details spill into stacktraces, blow their size and make them only readable by compiler experts. Although not specified in this ticket, those should be collapsed to clojure-friendly representation as well.

There are also many places where such representation should be applied:

- Default exception printer
- clojure.main
- clojure.repl
- clojure.stacktrace (used by clojure.test)

Also, maybe all those places need some sort of unification? E.g. why are there three {{(root-cause)}} implementations in clojure.core?

Prior work: I believe {{(pst)}} does some basic demunging, but not collapsing. It also doesn't handle complex cases of protocols etc. And it has to be explicitly called, which is not very convenient.

1 Answer

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-2456 (reported by tonsky)
...