Perhaps apart from attributes and the significant changes in the area of RTTI in Delphi 2010, there really isn’t much in the way of “HEADLINE NEWS” in this release. But that doesn’t mean there isn’t lots to appreciate, some of it dangerously subtle.
“Dangerous” because unless someone draws your attention to it, you might not even notice it.
As they occur to me I shall discuss some of these, usually with some explanation of why I think they are great, rather than just listing off the feature itself. I shall also present some ideas that these new features have given me for yet further improvements in some areas.
So first up in this occasional series….
Drag/Drop “Gutter-Balls”
I used the term “gutter-ball” recently when talking about this feature, so perhaps I’d better explain what they are before getting into dragging and dropping them.
“Gutter balls” are what I call those decorations that pop-up in the “gutter” alongside your code editor. Breakpoints (the red dots), bookmarks (the numbered squares), the execution point indicator (when stepping through code in the debugger) etc etc.
“Balls” is a bit of a misnomer because many of these decorations aren’t actually round, like a ball, but why let strict linguistic accuracy get in the way of a good nick-name?
Anyway, in Delphi 2010 many of these decorations can now be freely dragged and dropped. This to me a “a big deal”.
Breakpoints
I often use conditions on breakpoints, be that a pass count or some explicit condition expression to control when/if a breakpoint is active.
during a debugging session I’ll often find myself honing in on a bug, removing breakpoints and adding new ones as I get closer and close to where I suspect there to be a problem. Often the conditions on those new breakpoints are the same – or very similar – to those that I have removed, and I have to remember to setup those conditions on those new breakpoints each time.
Now I can simply drag an existing breakpoint, complete with conditions, and simply drop it where I now wish it to be. This may not save me a lot of actual time in absolute terms but it sure is going to make my debugging life easier.
The Execution Point
This is a potential minefield, but also a potential God-send.
Just as with breakpoints, when debugging and “stopped” on some line of code you can now drag the execution point and drop it somewhere else. When you resume execution or step, your code will execute from that new point.
WOAH! Hold on a minute, isn’t that, like… DANGEROUS!?
Absolutely. You could make a real mess of things by moving the execution point too far. In particular if you move it from within one function body to inside another, then your stack is almost certainly going to become corrupt, not to mention the fact that the new function body will not have been invoked with the necessary parameter assignments to registers etc etc so what happens when you resume execution is pretty unpredictable (some shortcut to restore the execution point to the “real” current execution point might be useful for those times when a thoughtless drag and a reckless drop create such a situation inadvertently).
You really do not want to move the execution point too far. But sometimes it is undeniably useful to be able to move it just a little.
Let us imagine you are debugging… you find yourself stopped on a line of code that you suddenly realise might be responsible for all your problems. Perhaps you forgot some trivial parameter check and are about to – incorrectly – call some function with a NIL parameter. Or perhaps you realised that your code just called a function with the wrong value in some variable passed as a parameter.
You know that you need to fix that, and you’ll come back to it shortly, but for now you’d like to see if that change would actually fix your problem. If only you could prevent the code from calling that function, or fix the value of that variable and call that function again with the correct parameter value – just as the changes in either case you are going to make would result in.
Well now you can.
Simply pick up the execution point and advance it FORWARD, beyond that function call, or edit the variable value (via the Expression Evaluator as usual – Ctrl+F7) and move the execution point BACKWARD, to repeat the call.
With Delphi’s lightning fast compilation performance, maybe it’s not such a big deal to have to halt the program, make the change, recompile and then re-test. But perhaps the application in question can’t simply or safely be Ctrl-F2‘d and has to be allowed to proceed through some lengthy shutdown procedure, and/or maybe recreating the problem to get to this point in the code to test it is non-trivial.
Sometimes a “quick fix” is just what the debugger ordered.
Bookmarks
This is not such a big deal – bookmarks were already very easily moved from one location to another simply by redeclaring the new location of the bookmark via the appropriate keyboard shortcut (Ctrl+Shift+<0..9>).
However, this might provide the inspiration for extending these newly movable gutter-balls even further… beyond their current limitations.
I will say however that a distinct improvement in this areas is the visual representation of bookmarks – these now much more clearly identify the number of the bookmark associated with them.
Limitations
The biggest limitation is that you can’t drag/drop between different tabs in the editor. If whilst debugging I step-in to a routine in another unit and realise that I now want my breakpoint in that routine I cannot drag it and drop it from one unit to the other.
Dragging and dropping the execution point between units is not a great idea – as mentioned, even moving it between different functions in the same unit is asking for trouble as it is, so let’s not worry about those.
Another problem is that when the execution point is on a line with a breakpoint you can’t get at the breakpoint to drag it! Any drag operation picks up the execution point, not the breakpoint “behind” it! If you want to move the breakpoint this creates a rather messy situation where you have to drag the execution point out of the way, drag/drop the breakpoint, then drag the execution point back to where it was.
Yuck.
Exceeding The Limitations – Breakpoints
For breakpoints there are two ways I can think of to get around the inability to drag/drop between units, and one of those would also fix the “execution point hides my breakpoint” problem:
- When dragging, if the mouse moves over an editor tab then switch the editor to that tab (you will notice when trying to drag breakpoints that “tabs” themselves are already “active” dropspots when dragging, in a way that the tab strip itself is not).
This doesn’t really need any explanation. The next idea will need a little more detailed exploration though I think…
- Provide some way of identifying breakpoints, perhaps by simply assigning some number to them, as with bookmarks. Ctrl+Alt+Shift+<0..9> might be available for this. Other key combinations could work but for the purposes of exploring the suggestion below, let’s assume this combination for now.
Pressing Ctrl+Alt+Shift+<0..9> where no breakpoint is currently assigned to that number should drop a new breakpoint at the current location or, if there are existing un-numbered breakpoints defined, pop-up a list of those breakpoints (“anchored” in the gutter, and keyboard navigable by default) to allow you to choose one to move to that location and assign the appropriate number to it.
Pressing Ctrl+Alt+Shift+<0..9> for a breakpoint that is already assigned to that number would simply move the appropriate breakpoint to the current location.
Breakpoint number assignments could of course be managed more directly via the existing Breakpoints list window in the IDE.
Pressing Ctrl+Alt+<0..9> (i.e. without the Shift modifier) for a breakpoint that is already assigned to that number would take you to the current location of that breakpoint, acting like a bookmark (I often find myself dropping a bookmark alongside a breakpoint).
10 may seem a rather limiting number for the total of such identified breakpoints, but in my experience if you have that many active breakpoints then in my view you aren’t debugging very effectively. A potentially contentious view, but I have yet to encounter a situation, even in highly complex problems, where more than 4 or 5 breakpoints are actively useful, and usually it’s only 2 or 3.
In fact, I think this “numbered breakpoint” idea has merit beyond being a work around for moving breakpoints between units.
Above and Beyond- Further Debugger Enhancements
With the ability to modify variable values via Expression Evaluation, and the ability to easily move the execution point around, we are pretty much as close to being able to modify our code “on the fly” during a debugging session as it’s likely to be possible to get with a fully compiled runtime/debugging environment.
A couple of fairly minor additions would make it even easier to effect that sort of behaviour and further enhance the debugging tools imho.
- Provide a Skip Over debugger shortcut key/toolbar command. The existing Step Over – F8 – allows you to execute the line of code at the current execution point and resume debugging at the next source line. Skip Over – Shift+F8 perhaps?– would allow you to advance the execution point over that same line of code without executing it.
- A Step Out command would also be useful. This would execute the code up to the end of the current function or procedure. i.e. equivalent to dropping a breakpoint at the end of the the procedure, running to that breakpoint, then removing the breakpoint – something I find myself doing a LOT when I find myself in a RTL function that I really am not interested in, when debugging with Debug DCU’s. [Update: Already present since at least Delphi 7! I don’t know how I’ve not noticed that before! It uses Shift+F8 already, so a “Skip Over” would need to use something else. Thanks to msohn and windwings for pointing that out]
- Provide a Skip Out command. This would work like Step Out but would jump to the end of the current function/procedure without executing the code between there and the current execution point. Equivalent to an EXIT call being made at the current execution point (for that reason, perhaps it should instead Skip to any finally block if the current execution point is within a try/finally… I don’t know if that’s possible for the debugger to determine however).
And finally…
- Make the Expression Evaluator window a modeless, dockable panel and/or allow in-place editing of watchlist or local variable values.
The IDE protects you from carelessly dragging the execution point to another function with a warning dialog box.
I like your ideas on debugger enhancements… Mostly. But UGH! For the love of all that is compiled, PLEASE don’t make the Evaluate window dockable. It’s bad enough that the ENTIRE REST OF THE UI tries to stick itself to any edge of any pane it can find, and carve itself out a nice big chunk of screen real estste that belongs to my actual code view, by default, when I’m just trying to get them out of my way. That’s a horrible feature in Visual Studio that got Me-too-ed into a horrible feature in Delphi. Please don’t even SUGGEST that the last remaining debug window that knows how to behave itself like a proper floating debug window should go get itself gluttonized too!
[/rant]
OK, enough of that. I really did like the rest of the post, though…
LOL
Well the key is the “able” part… the modal nature of the Evaluate Expression window can be irritating. My main point was to make it modeless – to fit in with the rest of the IDE framework that would mean making it dockable, but nobody could force you to actually dock it… you could leave it floating if you prefer. 🙂
Nice ideas altogether.
BTW: there already is (at least since D2007) something very similar to Step Out: Run Until Return which uses Shift+F8. Very handy if you step into lower level methods like the RTL.
Another Breakpoint suggestion: restore the last breakpoint that was deleted. I don’t know how often I inadvertedly pressed F5 only to realise that my previously setup breakpoint with conditions etc. is now gone.
“A Step Out command would also be useful.”
Already present. See ‘Run | Run until Return’ – shortcut: Shift+F8.
HTH
@msoh + windwings: Thanks for that! How I have not noticed that before?!
I just checked and never mind D2007, it’s been there since at least D7!!
(put’s the mockers on using Shift+F8 for Skip Over though, darn) 🙂
Mason, I may have misunderstood your rant, but you can hold down Ctrl while dragging windows to have them not dock by default. There’s also a docking setting in the options to reverse that (have to hold Ctrl to dock). I personally like the docking however, it’s very flexible and you don’t have to dock what you don’t want to. Love the desktop settings too. Going to a widescreen monitor and customizing the ide to the way you work is key.
@Joylon: I’m a little bit confused here. What modal Evaluate Expression window are you referring to? The one I’m talking about is Evaluate/Modify (CTRL-F7), and it’s been a modeless floating dialog for as far back as I can remember.
@Mason: This is priceless… do you know, it’s simply never occurred to me that the dialog even *might* be modeless!! I think the fact that it didn’t dock was the cue that had misled me.
(Not very important fact)
The Shift+F8 key (run until return) works in D5, but not in D2, so now it’s narrowed down to D3, 4 or 5 for introducing this feature.
What I miss dearly, is a little more intelligence in the debug inspector & watches pane; Let me explain : When I inspect an instance of a class type, I always find myself doing these steps:
1. Evaluate ‘aInstance.ClassType’ – let’s say it returns TWhatever
2. Evaluate ‘TWhatever(aInstance)’.
Both steps involve a bit of typing, and could easily been done automatically. What beats me, is why the Delphi IDE doesn’t offer this very usefull, time-saving (and easy to implement) feature per default!
I attended the 2010 release event and I was totally disapointed. There was nothing new and in fact there as been little of real substance added to Delphi since ver. 7. All the exciting stuff is being done by 3rd party developers like Developers Express. I have been developing business application software for over 20 years, and I have been using Delphi since ver. 3. Most of my current work is done in Delphi 7, I purchased a copy of 2009 and have yet to move my main projects over because there is no real reason to do so. You will be amazed that I have never used or found a use for breakpoint or examining the CPU registers. The complier is fast enough that you write a couple of line compile and test and if there is a bug fix it then and move on. I also talked to a couple of people at the 2010 release event and found that they were all using delphi 5 for in house projects. I think that the only way that Delphi will survive the onslaught of C# and .net will be if more people would actually write commercial ie for sale for $ applications. How many people in NZ actually use Delphi to create commercial applications.