visuald icon indicating copy to clipboard operation
visuald copied to clipboard

Improve stepping over opApply

Open TurkeyMan opened this issue 9 months ago • 5 comments

There's a little usability issue that's always bugged me, but I never bothered to log an issue. It's like this:

foreach (x; collection) // <- place breakpoint here, press F10 (step-over)
{
  x.doSomething();
}
nextLine(); // <- cursor moves to here, completely skipping over the loop

In cases where collection has an opApply function to implement the foreach behaviour, if the cursor is at the foreach statement, and you press F10, instead of stepping into the first line of the loop inner as usual, since the opApply is essentially just a function call, the debugger steps-over the opApply and goes straight to nextLine(). This gives the false impression that the collection is empty; but actually, the reality is that because opApply was a function call, it just stepped over the entire loop. Since opApply is rare, it's easy to miss/forget this detail, and so I find myself constantly making the improper assumption that the collection was empty, which occasionally leads down a rabbit hole chasing other explanations for a problem...

I have no idea how to fix this; it seems like a hard problem... but I wonder if any creative solutions are possible? Maybe a breakpoint could silently be placed at the entry to the loop-body lambda when the user presses step-over; but it's hard to imagine how to detect the conditions to enable a hack like that.

I guess there could be a solution that involves aggressive/forceful inlining of the opApply and the lambda?

TurkeyMan avatar Mar 08 '25 03:03 TurkeyMan

Indeed not an easy problem. You can use "Step into specific" to get immediately to the loop body lambda (if you know which of the mangled symbols is the right one), maybe that can be automated somehow. But it doesn't get simpler when returning from the lambda: in normal cases with "Step over", you will probably not want to step through the opApply code but the next iteration inside the lambda or continue after the loop.

Inlining might help in some cases, but might also make it more difficult to detect opApply code that should be skipped when stepping over.

rainers avatar Mar 08 '25 10:03 rainers

Mmmm, it seems like a really hard problem. I wonder if any other languages have a similar situation that pops up often, and have any novel solutions for their cases...

TurkeyMan avatar Mar 08 '25 11:03 TurkeyMan

Does the MS debuginfo support arbitrary metadata? I wonder if the compiler could tag the symbol for the lambda onto the foreach line entry when foreach calls an opApply, then maybe the debugger can conveniently reach the foreach body? There's a few rough edges caused by being a C++ debugger and D just needing to know some extra stuff... how well do you know MS's debuginfo format?

TurkeyMan avatar Apr 26 '25 06:04 TurkeyMan

I used to know CodeView pretty well, but not the newer extensions added in recent years. I think it should be possible to pass arbitrary information from the compiler to the debugger, worst case by encoding it into special symbols.

But so far, the debugger extension only evaluates expressions and does not do any execution control. Going in that direction would be a major effort.

Maybe a bit invasive, but instead of opApply you could also implement a forward range. That should work as expected when stepping over a foreach loop. The debugger can even display the range in the watch window (if enabled in the debugger options). That's not translated to the asynchronous function execution, though.

rainers avatar Apr 26 '25 15:04 rainers

Yeah I guess that's probably the way forward. Some algorithms are not so simple/efficient to range-ify.

TurkeyMan avatar Apr 26 '25 16:04 TurkeyMan