8 ms·
In CL/SLIME, you add `(break)` to the code where you want it to stop and hit `C-u C-c C-c`. Then you run the code you care about and you should be able to step
by fiddlerwoaroof 3y ago
In CL/SLIME, you add `(break)` to the code where you want it to stop and hit `C-u C-c C-c`. Then you run the code you care about and you should be able to step from the break.
This is a common complaint about CL, but my experience is that the utility of debuggers is vastly over-stated. It’s a nice trick in Java or C/C++ or JS (in Chrome), but I've never found a debugger to significantly improve my workflow and the “repl-driven development” paradigm of CL solves the problem differently by increasing iteration speed.
- jonathankoren 3y ago> This is a common complaint about CL, but my experience is that the utility of debuggers is vastly over-stated. It is possible to patch a running CL system by simply setting a breakpoint and then revaluating a function. I am unaware of any other language that is possible in. This Lisp feature is only made possible through a debugger. I know, because I've done it.
- _19qg 3y ago> It is possible to patch a running CL system by simply setting a breakpoint and then revaluating a function. It's also possible to change a running CL system without setting a breakpoint and/or re-evaluating a function. > I am unaware of any other language that is possible in. Start with Smalltalk and then search for more.
- fiddlerwoaroof 3y agoYeah, although the debugger in lisp is also lacking a lot of features people tend to expect: stepping through code, in particular, is painful unless you recompile with DEBUG 3
- xkriva11 3y agoThere are even languages that can do more crazy things than CL or Smalltalk. For example, in Sinclair BASIC, if you put a breakpoint at some position on the line, you can even modify the rest of the line and continue with execution from the breakpoint without the need of restarting anything.
- _19qg 3y agoIf we are using a Lisp interpreter, which executes s-expressions, we can do similar things, here an example using LispWorks, which has both a compiler and a source-level Lisp interpreter. The function FOO has a BREAK. CL-USER 76 > (defun foo (a) (+ (break) (sin a))) FOO CL-USER 77 > (foo 10) Break. 1 (continue) Return from break. 2 (abort) Return to top loop level 0. Type :b for backtrace or :c <option number> to proceed. Type :bug-form "<subject>" for a bug report template or :? for other options. We are in the break lets get a quick backtrace and move to the right stack frame: CL-USER 78 : 1 > :bq INVOKE-DEBUGGER <- BREAK <- FOO <- EVAL <- CAPI::CAPI-TOP-LEVEL-FUNCTION <- CAPI::INTERACTIVE-PANE-TOP-LOOP <- MP::PROCESS-SG-FUNCTION CL-USER 79 : 1 > :n Call to INVOKE-DEBUGGER CL-USER 80 : 1 > :n Call to BREAK CL-USER 81 : 1 > :n Interpreted call to FOO What is the current source? CL-USER 82 : 1 > :lambda (LAMBDA (A) (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 8220104A8B>)) (DECLARE (LAMBDA-NAME FOO)) (+ (BREAK) (SIN A))) Let's change the code: CL-USER 83 : 1 > (setf (third (fifth *)) '(* a 4)) (* A 4) Let's see the new code. CL-USER 84 : 1 > :lambda (LAMBDA (A) (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 8220104A8B>)) (DECLARE (LAMBDA-NAME FOO)) (+ (BREAK) (* A 4))) Move to the BREAK stack frame and return 2 from there: CL-USER 85 : 1 > :p Call to BREAK CL-USER 86 : 1 > :ret 2 42 As you can see, we have changed the running source code, without the need to restart anything.
- HexDecOctBin 3y ago> In CL/SLIME, you add `(break)` to the code Having to modify code to add/remove breakpoints is pretty much the definition of jankiness. Can Emacs+SBCL show a list of all breakpoints, for example? > This is a common complaint about CL, but my experience is that the utility of debuggers is vastly over-stated. I disagree. A debugger gives you insight into the state of the program. It makes no sense to burn neural cycles trying to track program's state manually when a debugger can visualise it in multiple views and forms. Frankly, during development, I always run my code in a debugger, just to be able to confirm my assumptions on a granular level whenever I want to. > the “repl-driven development” paradigm of CL In my experience, trying to substitute a proper debugger with REPL leads to unnecessarily small functions, which then lead to very deep call stacks and undocumented assumptions about pre- and post-conditions of all those tiny functions. However, CL is specially bad about this anyway, since every `let` binding adds a new nesting, making long linear functions unreadable (either due to deep nesting, or due to predeclaring all variable as in ANSI C). Scheme with its `define` is much better in this regard.
- medo-bear 3y agoSince I dont use VS Code I'm not sure if I follow but most of these things you describe are in fact available, at least with Emacs+SLY (Common Lispers either use Emacs+SLIME or Emacs+SLY). What you call "non-janky" break points are referred to as Stickers in SLY, which on the whole seem to me a far more advanced idea than what you say VS offers. See https://joaotavora.github.io/sly/#Debugger https://joaotavora.github.io/sly/#Debugger
- HexDecOctBin 3y agoI am not talking about VS Code, but Visual Studio (or any other visual debugger from the last 30 years). Sly's UI seems to be similar to that of GDB, which is exactly what I am talking about. I would suggest trying out and comparing GDB and one of its numerous GUI frontends to understand why a GUI with multiple views displayed simultaneously (i.e., you can keep track of different parts of state on different parts of screen) and automatically (i.e., display doesn't require interaction) improves debugging experience.