Stream: ideas

Topic: debugging in an interpreter


view this post on Zulip Richard Feldman (Feb 01 2025 at 22:15):

we've been talking about using an interpreter for dev builds, but we haven't really talked about the pros and cons of that when it comes to debugging. So I'd like to discuss!

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:16):

one thing that comes to mind is that it's easier to write your own debugger in an interpreter

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:18):

for example, several interpreted languages I've used have keywords like breakpoint that you can just put in the code, and then when execution reaches there, it just halts and gives you an interactive prompt where you can do typical debugger things like print a backtrace, step forward, etc.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:18):

I think it will essentially strictly be better

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:18):

it's strictly easier to make a great experience I'd say

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:18):

The ones caveat is it will be more likely to hit difference between debug and optimized builds

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:18):

but then we get into the question of consistency

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:18):

yeah exactly

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:19):

With the interpreter we can literally drop into a full repl at any point in the program

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:19):

like "everything is great but then I add --optimize and suddenly everything is different and worse"

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:19):

To be fair, if we were gonna make a dev backend anyway, it is really no different in terms of correctness

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:20):

Both are distinct from llvm in terms of correctness

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:25):

oh sure I just mean like if we put a repl in there (for example), we should think about whether we want to replicate that ability in non-interpreter backends

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:26):

Ah, so more a question of how do we debug optimized code?

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:27):

yeah, so one possible design is:

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:36):

Sure. In my mind, the baseline is llvm for everything. Having a dev backend improves compilation speed, but otherwise is equivalent to the llvm backend. Having an interpreter gives debugging super powers in comparison. That said, it is not easily distributable.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:36):

So yeah, having roc build always use llvm makes sense.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:38):

Though for some cases, always having the interpreter may be really nice (dynamic plugins where perf isn't too important)

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:40):

totally

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:44):

a possible variation on that design could be that we have a cli flag for roc build which lets you bundle in our own fancy debugger instead of (or maybe in addition to?) debuginfo

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:45):

so that you could do a "break into a repl" thing even in a standalone build that you're using for (for example) a plugin that isn't being launched by the roc CLI

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:45):

This would be interpreter only?

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:47):

feels like we could do it in llvm too, but it would be (a lot) harder :stuck_out_tongue:

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:49):

a sketch of how a llvm "drop into a repl right now" build could work:

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:50):

I'm not saying we should do this soon or anything, just thinking ahead to like "is it possible that we could offer this functionality and have it work both with and without --optimize"

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:50):

I honestly don't think it would work out well, but it could be attempted.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:51):

To be fair, gdb and lldb have plugins that can help a lot with controlling cleaning, but it is nothing near an interpreter really.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:52):

Also, the way to offer this the easiest is probably to jit. Then there is no true optimized backend. Instead any code can be run jitted and faster or via the interpreter a step at a time.

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:52):

do you think it wouldn't work well because of --optimize having stripped away relevant intermediate things?

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:54):

Think about profiling and how poorly the info often maps back to the original source code. That level of mapping is what you are dealing with when trying to figure out running some form of repl.

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:55):

that's fair

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:55):

Even without stripping any debug info all the merging and moving around of code and various optimizations make the mapping very poor

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:55):

So trying to walk that similar to a repl is just tough

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:55):

Brendan Hansknecht said:

Also, the way to offer this the easiest is probably to jit. Then there is no true optimized backend. Instead any code can be run jitted and faster or via the interpreter a step at a time.

I definitely think we should always support the current level of "optimize as much as possible"

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:56):

Yeah, I agree.

view this post on Zulip Richard Feldman (Feb 01 2025 at 22:56):

if that means some tooling becomes impossible, that's better than having those levels of performance being impossible

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 22:59):

I do think it should be theoretically possible to run an optimized build but have a breakpoint with logic to launch into the interpreter at that point. That may help with some optimized debug. Though not exactly sure how you would exit the interpreter and go back to the optimized code. Might have to block function inlining and do this at the function level to make it possible to switch between the two.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 23:00):

Assuming roc has no bugs (few code gen bugs vs interpreter for correctness), theoretically the only disadvantage of debugging in the interpreter is execution speed. Cause optimized builds should never change observable behavior in roc unlike in some other languages.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 23:01):

So there may not be much demand to debug optimized builds anyway.

view this post on Zulip Brendan Hansknecht (Feb 01 2025 at 23:06):

As a note, I think this message really touches what can be done with traditional executable debugging and tools like lldb:
Andrew Kelley said:

Richard Feldman said:

so the (very serious) debuggability/ergonomics downside we've had of doing SoA in Rust may just be a non-issue in Zig

with the llvm backend it's still a pain in the ass to debug MultiArrayList, however, with our self-hosted backends (currently x86_64 only, aarch64 to follow next) we have custom dwarf + lldb fork that recognizes zig std lib types and makes debugging really nice. same thing goes for hash maps

this project may be interesting to watch long term since jacobly (author of above lldb fork as well as zig's x86_64 backend) has taken an interest in it

Still can be pretty decent, but not nearly as flexible as an interpreter and repl.


Last updated: Jun 16 2026 at 16:19 UTC