Search code examples
debuggingemacscommon-lispsbclslime

What are efficient ways to debug Common Lisp in Emacs and SLIME?


I'm wondering what are some efficient ways to debug Common Lisp interactively using Emacs and SLIME.

What I did before: As someone who learned C and Python using IDEs (VS and PyCharm), I am used to setting break points, adding watches, and do stepping. But when I started to use CL I found the debugging workflow fundamentally different. I did not find good ways to set break points, step though lines and see how variables change.

The dumb method I used was adding "print" in code and run the code over and over again, which is very inefficient. I know we can "inspect" variables in SLIME but not sure how to do it interactively.

What I found: I came across this video on the development of a Morse code translator recently, and it shows a complete process of how to debug interactively in SLIME, which has been very informative and enlightening. It is as if we could "talk" to the compiler.

What I want: I searched online but found minimal tutorials demonstrating how an experienced Lisper actually develop and debug their programs. I am eager to learn such experiences.

  • How to debug interactively?
  • What are some good practices and tips? How to add breakpoint and step?
  • What shortcuts / tools / workflow do you use most frequently / find most useful when debugging?

Solution

  • There is a number of things you can do:

    • You can trace a function call (see TRACE and UNTRACE in Common Lisp or slime-toggle-trace-fdefinition*). This helps with recursive calls: you can see what you pass and what they return at each level.
    • Standard thing: add (format t ...) in places. I guess, no need to comment.
    • If the code breaks, you will get into debugger. From there you can examine the stack, see what was called and what arguments were passed. See @jkiiski link: it has really great information about it, including (break) form that will act as a breakpoint and get you to debugger. Spoiler alert: you can change the values in the inspector, you can change and re-compile your code and restart from (almost) any place in the stack.
    • Last but not least: to debug macros, you will need slime-macroexpand-1 (wrapper over MACROEXPAND-1) and even better C-c M-e for macro stepper.

    One last advice: if you are to do a serious debugging, include (declaim (optimize (debug 3))) in your file, otherwise some CL implementations have a tendency to optimize away the calls on the stack or make arguments inaccessible.