7

Many times when I try to write some function I get exception. That is normal. In Java you can find place and reason why exception occures but in clojure exception texts just make me crazy. Is there some tips how to read exceptions in clojure and how to find where in code exception happens and why?

For example I will take some code:

(do
 (list?)
 (list? [])
 (list? '(1 2 3))
 (list? (defn f [] (do ())))
 (list? "a"))

when I call this function in REPL I will get

java.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$list-QMARK- (NO_SOURCE_FILE:46)

which do not help me much to find the problem in second line. In little more complicated code it will give almost no information. (Of course it tells look at list? in some there is wrong number of arguments.) Is it wrong that I try to write code in REPL? How to read exception mesages in REPL? Is there way how to get better information about exceptions in REPL?

boucekv
  • 1,220
  • 2
  • 20
  • 47
  • Possible duplicate of http://stackoverflow.com/questions/2352020/debugging-in-clojure. – A. Webb Feb 19 '13 at 14:52
  • Also related to http://stackoverflow.com/questions/14297079/why-are-clojure-stacktraces-so-long/14298576#14298576 – JohnJ Feb 19 '13 at 22:43

2 Answers2

6

You can use clojure.stacktrace: http://richhickey.github.com/clojure/clojure.stacktrace-api.html

Usage:

(use 'clojure.stacktrace)
(/ 1 0)
(e)

Output:

java.lang.ArithmeticException: Divide by zero
 at clojure.lang.Numbers.divide (Numbers.java:156)
    clojure.lang.Numbers.divide (Numbers.java:3691)
    user$eval954.invoke (NO_SOURCE_FILE:1)
    clojure.lang.Compiler.eval (Compiler.java:6511)
    clojure.lang.Compiler.eval (Compiler.java:6477)
    clojure.core$eval.invoke (core.clj:2797)
    clojure.main$repl$read_eval_print__6405.invoke (main.clj:245)
    clojure.main$repl$fn__6410.invoke (main.clj:266)
nil
Marius Danila
  • 10,311
  • 2
  • 34
  • 37
2

Acquire org.clojure/tools.trace.

user=> (use 'clojure.tools.trace)

Let's try a dotrace (changed up the order to make things more interesting):

user=> (dotrace [list?]
  #_=> (do
  #_=>  (list? [])
  #_=>  (list? '(1 2 3))
  #_=>  (list?)
  #_=>  (list? (defn f [] (do ())))
  #_=>  (list? "a"))
  #_=> )
IllegalStateException Can't dynamically bind non-dynamic var: clojure.core/list?
  clojure.lang.Var.pushThreadBindings (Var.java:353)

Hmm...

user=> (.setDynamic #'list?)
#'clojure.core/list? 

Let's try that again:

user=> (dotrace [list?]
  #_=>   (do
  #_=>   (list? [])
  #_=>   (list? '(1 2 3))
  #_=>   (list?)
  #_=>   (list? (defn f [] (do ())))
  #_=>   (list? "a")))
TRACE t1216: (list? [])
TRACE t1216: => false
TRACE t1217: (list? (1 2 3))
TRACE t1217: => true
TRACE t1218: (list?)
ArityException Wrong number of args (0) passed to: core$list-QMARK-  
  clojure.lang.AFn.throwArity (AFn.java:437)

Aha! Made it to (list?) before the exception.

A. Webb
  • 26,227
  • 1
  • 63
  • 95