I'm coming around to the idea that, when it comes to optimizations, we should treat dbg like we treat functions in stack traces.
that is, function names might not be available in stack traces because they might have gotten inlined away and not be recoverable. Similarly, if we allow our (future) optimizer to optimize pure functions that contain dbg, under the assumption that it's acceptable for a dbg not to run because the section of code it's inside was just no longer necessary after optimizations, then that seems like the right outcome
I do think it's important for dbg not to be always removed in --optimize, because I may be trying to debug something that requires optimizations in order to be usable at all
but I also think if we allow dbg to defeat optimizations, then it means I might end up in a confusing scenario where I add dbg to try to figure out what's going on, and it gives me an inaccurate mental model of how things are being optimized
because if adding dbg to a function can cause it to be optimized differently (because the optimizer has to keep dbg around due to its side effect), then we have a sort of "Heisenberg Uncertainty Principle" situation - adding the dbg to try to observe what's going on causes what's going on to change
whereas if we let the optimizer remove them, then the absence of the dbg printing anything tells me something about what's being run
the coolest version of this, which I think might be viable if we only remove dbg in our own optimization steps (as opposed to, say, allowing LLVM to optimize them out too), would be to give a compiler warning if you put a dbg in a place where it gets optimized out
like "warning, this dbg will not actually print anything because it gets optimized out"
which might be tricky in that whether it gets optimized out might theoretically vary based on specialization - e.g. in some specializations it gets optimized away, but in others it doesn't
so the wording might have to be careful there
but that would be helpful in communicating "hey the reason you're not seeing this dbg is because it got optimized away, not because the surrounding code didn't get run"
How would they get optimized away?
Like what optimization would remove them?
Llvm would never remove them.
I can't think of a roc optimization that would make sense to remove them either
let's say we have |> List.keepIf bar and we figure out that bar does a dbg and then always returns true in one particular specialization
and we figure out that
bardoes adbgand then always returns true in one particular specialization
Just to check my understanding; we don't have anything that can figure this out now right? We would need to write code that can do that.
Let's pretend bar is:
bar = \x ->
dbg x
Bool.true
I think we should either remove the dbg 100% of the time or 0% of the time. Otherwise, you just frustrate users.
It will definitely confuse users the first time. I do see value in a dbg that is tied to optimization, perhaps it should be a different keyword like optdbg :thinking:
Personally, I would lean to something like:
dbg in local imports on by default in un-optimized buildsdbg by default for optimized buildsdbg in optimized buildsEither way, I think optimizing away dbg sometimes is a bad idea. dbg is for understanding a complex program. Optimizing it away sometimes makes that very hard to do.
Last updated: Jun 16 2026 at 16:19 UTC