This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-09
Channels
- # announcements (1)
- # babashka (14)
- # calva (8)
- # chlorine-clover (3)
- # clerk (6)
- # clj-kondo (27)
- # cljdoc (20)
- # clojars (6)
- # clojure (53)
- # clojure-denver (8)
- # clojure-europe (17)
- # clojure-nl (1)
- # clojure-norway (270)
- # clojure-uk (5)
- # clojurescript (35)
- # community-development (7)
- # cursive (12)
- # datalevin (3)
- # datomic (26)
- # etaoin (23)
- # exercism (1)
- # hyperfiddle (3)
- # java (14)
- # nrepl (2)
- # off-topic (12)
- # pathom (3)
- # portal (44)
- # practicalli (2)
- # reagent (7)
- # releases (1)
- # shadow-cljs (13)
- # timbre (3)
- # xtdb (4)
When using the Calva debugger, I would like to catch exceptions and be able to navigate the stack using the debugger. How can I do that? In the attached screenshot, evaluating (g 1)
leads to the debugger activating as expected at the breakpoint. But evaluating (g 'a)
just prints the exception in the REPL without the debugger activating. I tried various ways of adding instrumentation via #dbg
etc, but to no avail. What is the correct way of doing this?
The debugger doesn't support catching exceptions and navigating the stack trace, but in your example, (f x)
is being evaluated before the debugger stops to show you the result of it (your #break
applies to the whole (f x)
expression).
If you change g
to:
(defn g [x]
(f #break x))
then evaluate (g 'a)
, you'll see the debugger start and show you the value of x
before (f x)
is evaluated, but when you continue execution the exception will be thrown and the debugger session will end.> be able to navigate the stack using the debugger. Also, what exactly do you mean by this?
To take an example from Python in PyCharm, if I run this in Debug mode, and the exception is thrown, PyCharm automatically drops me into the debugger and gives me the pane on the bottom left, where I can select the frame I want to look at and see the values of all variables in the respective scopes in the bottom right. As far as I am aware, none of the various Clojure development environments support this. (Would love to be mistaken though, pointers very welcome.)
To some extent even more useful, the PyCharm debugger has this "Console" tab, which essentially gives a REPL that has the local variables at the point where the exception raised in scope, for interactive exploration. Moreover, this talks to the frame selector on the debugger tab: if I select a different frame, the console now has the variables in that frame's scope available. Even forgetting about the nice UI, any way to "look" at the local variables at any frame of a clojure stacktrace would be super-useful to figure out what and where an exception was caused.
I have figured out how to do this in IntelliJ/Cursive. See the #C0744GXCJ channel. Key over there is to activate "Exception Breakpoints", make sure you break on caught exceptions, and set a "catch class filter" to include clojure.lang.Compiler
. Does something similar exist in Calva?
Thanks for the info. This does not exist in Calva. If I understand correctly, Cursive, due to it being an IntelliJ extension, has better, more integrated Java support, which may be playing a role in that feature.
I will say though that while I added the debugger features to Calva, I don't use the Calva debugger. I instead prefer the repl over a step debugger, particularly using https://blog.michielborkent.nl/inline-def-debugging.html to capture variable values from code execution. https://github.com/AbhinavOmprakash/snitch is a really helpful library that I've more recently started using. It makes using inline defs more convenient (it adds them for you, invisibly, using macros).
A couple of other debugging libraries that you may find interesting are https://github.com/vvvvalvalval/scope-capture and https://github.com/jpmonettas/flow-storm-debugger. Flow-storm is a trace debugger that let's you go backward and forward in time and see the values of bindings as you navigate.
Anyway, maybe you are familiar with some of the above methods but prefer a step debugger, and to each their own. I just wanted to share in case you find some of those methods useful, interesting, or appealing.
This is great, really appreciate the advice. Given how varied/flexible Clojure's tooling is, it is super-useful to hear about other people's workflows and best practices.