Breakpoints and stepping
A breakpoint pauses the program on a line you choose. Once it is paused, the step commands run it one statement at a time, and Set Next Statement moves the point where it goes on. This page also describes the panel that opens when a run-time error stops the program.
Breakpoints
Set and clear a breakpoint
Click in the margin of the code editor beside a line, or put the caret in the line and press F9 (Debug → Toggle Breakpoint). Either one sets the breakpoint at once, or clears it if the line has one. Nothing is asked, and no line is selected first. A breakpoint belongs to a code editor: a form designer has no margin, and F9 does nothing there.
The margin shows four marks:
| Mark | Meaning |
|---|---|
| A red dot | A breakpoint. |
| A faint dot | The pointer is over the margin of this line, and a click would set a breakpoint. It shows on every line except the one with the arrow. |
| A yellow arrow | The program is paused on this line. |
| A yellow arrow over a red dot | The program is paused on a line that has a breakpoint. |
To clear every breakpoint of the project, choose Debug → Clear All Breakpoints (Ctrl+Shift+F9). It clears the breakpoints in every file, open or not. It asks for no confirmation.
On the line that has the arrow, a click without dragging toggles a breakpoint too. A press that lasts longer than a fifth of a second starts a drag of the arrow instead; see Set Next Statement.
What a breakpoint does
A breakpoint is a line number and nothing else. There are no conditions, no hit counts, no log points and no disabled breakpoints, and there is no list of breakpoints: the margin of an open file is the only place that shows them. There is also no Run to Cursor command. F6 runs the procedure at the caret, which Running describes.
A breakpoint moves with the text. If you insert lines above it, the dot stays with its line, and the next run stops at the moved line.
The margin takes a breakpoint on any line, including a blank line, a comment and the Module line. The glyph stays, but a line that does nothing never stops the program. A Sub or Function line, a Dim with an initializer such as Dim n As Long = 7, a Next (at every pass) and an End Sub do stop it. A breakpoint in the Click procedure of a form stops the program when the button is clicked.
When a stop is in a file that is not open, the IDE opens the file. With Single-Click Preview on in IDE Options, it opens as a preview tab.
Where breakpoints are kept
The compiler keeps the breakpoints of each file. A breakpoint survives Restart the compiler, whether or not you saved the project, because the IDE sends its list to the new compiler. A breakpoint is not part of the source: Export Project writes no trace of one. Setting or clearing one marks the project as changed, so closing the project asks to save it.
The Allow Breakpoints (Debuggable) item of Debug → Debugger Options turns breakpoints off for the whole project. While it is off, you can still set breakpoints and the margin shows them, but none stops the program. Turn it on, and they stop it again from the next run. Debuggable describes the project setting, and the Debuggable attribute changes it for one module, class or procedure.
What happens at a stop
A breakpoint, a step, a Stop statement, the Break command and a run-time error all stop the program in the same way. At the stop:
- The editor opens the file, if it is not open, and puts the caret at the line and column of the stop.
- The whole line gets a pale yellow background, and the yellow arrow appears in the margin. Themes can change the background, which is the theme property
DebugLineBackColor. - The panels fill: Call Stack, Variables and the watches, and the Memory pane if it is shown. The IDE evaluates every watch.
- The IDE shows its own window and asks for the keyboard focus.
The arrow and the background belong to the top frame, the procedure that is running. When you click another row in the Call Stack, the background moves to that frame’s line, in that frame’s file, and no arrow is drawn in the margin of any editor. The Variables panel, the watches, the console and the hover then all use that frame.
The marks, and what the panels hold, are cleared the moment the program continues, steps or ends.
A Stop statement shows the arrow and the background, and no error panel. A Debug.Assert with a false condition shows the error panel, as below describes.
Step commands
While the program is paused, three commands run it one step at a time. The panels empty while the program runs the step, and fill again at the next stop.
- Step Into (F8 or F11)
- Runs the next statement. When the statement calls a procedure of the project, the program stops on the
SuborFunctionline of that procedure. - Step Over (Shift+F8 or F10)
- Runs the next statement as one step, including any procedure it calls. A
RaiseEventruns its handlers. - Step Out (Ctrl+Shift+F8 or Shift+F11)
- Runs the rest of the current procedure, and stops in its caller on the line after the call; the note below describes a case in which it does not. Step Out from
Mainends the run. The Debug menu has no Step Out item: use the toolbar button or the keys.
A procedure in another file opens in the editor when you step into it, as a preview tab when Single-Click Preview is on.
At the End Sub of a procedure whose local variables hold objects, a step goes into a frame named {class_final_destruction} and then into the Class_Terminate procedures of those objects. A step off the End Sub of the Click procedure of a form lets the program run on, and the form waits for input again.
Note
In twinBASIC BETA 1005, once the program has stopped at a breakpoint, no step stops in a caller of the procedure it stopped in. Step Out, F8 at the End Sub and Step Over all run the caller on until the next breakpoint or the end of the program. Steps inside the procedure, and into the procedures it calls and back out to it, work. To stop in the caller, put a breakpoint there, or stop on the line of the call and step into the procedure.
Set Next Statement
Debug → Set Next Statement (Jump To Line) (Ctrl+F9) makes the line that has the caret the next one to run. The arrow moves to it, and the lines in between do not run: a Debug.Print that the jump skips prints nothing. The jump can go to a later line or to an earlier one.
You can also drag the arrow. Press on it and hold for a fifth of a second. The pointer becomes a grabbing hand and the arrow shrinks. Move over the margin, where a faint arrow follows the pointer, and let go over the line you want. The result is the same as the command. A shorter press is a click, which toggles a breakpoint.
The jump works inside the paused procedure only. A blank line, a line of another procedure and a line of another file give no result: the arrow stays, and nothing is written to the console. The IDE sends the compiler the line number and no file name, so with the caret in another file than the paused one, the number is taken in the paused file.
Break On All Errors and Debuggable
The two items of Debug → Debugger Options turn project settings on and off. Each writes its setting into the project’s Settings file. A change to Allow Breakpoints (Debuggable) marks the project as changed, applies from the next run, and needs no restart of the compiler.
- Break On All Errors
- Off by default. Then an error that is raised while
On Error Resume NextorOn Error GoTois in effect goes to that handler, as usual. When it is on, the program stops at the failing line even there, with the same error panel as an error that nothing handles. Ignore (Resume Next) then skips the line. UnderOn Error Resume Next,Err.Numberstill holds the error afterwards, so code that checks it sees the error. F5 runs the failing line again, and the program stops on it again. UnderOn Error GoTo, the handler never runs. The project setting is Break On All Errors. - Allow Breakpoints (Debuggable)
- On by default; the item shows its tick when the setting is absent from the
Settingsfile. See Where breakpoints are kept and Debuggable.
When a run-time error stops the program
A run-time error that no On Error statement handles stops the program on the line that raised it. It stops the same way whether the program was started with Run → Start (F5), from the ▶ run link above a procedure, or by a [RunAfterBuild] procedure. With Break On All Errors on, a handled error stops it too.
The examples below use this procedure. On the fourth pass through the loop, idx is 7, past the last index of a, which is 5:
Public Sub FillTable()
Dim a(5) As Long
Dim i As Long
Dim idx As Long
Dim total As Long
For i = 1 To 6
idx = Choose(i, 1, 3, 5, 7, 2, 4)
a(idx) = i * 10
total = total + i
Debug.Print "i = " & i & ", idx = " & idx & ", total = " & total
Next i
Debug.Print "loop finished, i = " & i & ", total = " & total
End Sub
Where it stopped, and what the variables hold
The editor opens the module, highlights the whole failing line, a(idx) = i * 10, and puts a yellow arrow in the margin beside it. Under the line, an error panel shows:
- Run-time error 9 (00000009): the error number, then the same number in hexadecimal;
- DESCRIPTION: and the error’s description, here Subscript out of range;
- four buttons: Try Again (Resume), Ignore (Resume Next), Stop and Search Online.
The number is the one Err.Number holds. When the error was raised with Err.Raise and a source, a SOURCE: row with the source text shows below the buttons. When the compiler gives no header, the panel is titled ERROR OCCURRED. Nothing about the error is written to the Debug Console. The panel’s × only hides the panel.
A false Debug.Assert opens the same panel, with the header Run-time error -353703420 (EAEAEA04) and the description Assertion FAILED. F5 there runs on past the assertion. A Stop statement opens no panel.
The other panes show the state of the program at the failing line:
- Call Stack lists the chain of calls, the failing procedure first, each with its file and its
line:column. Here that isFillTable, then the procedure that called it, if there is one. Clicking a row opens that file at that line, and Variables then shows that procedure’s variables. - Variables shows the failing procedure’s Locals, already expanded:
iis 4,idxis 7 andtotalis 6. The array shows as{array of 6 elements}until it is expanded. - Holding the mouse pointer over a variable in the editor shows its value; see Hover.
Reading and changing values in the Debug Console
The input row at the bottom of the Debug Console runs a line of code inside the stopped procedure:
? iprints4, with a(time taken: …)line after it.Debug.Print idoes the same.ion its own is refused, with(compile error: Expression is neither used nor assigned).idx = 5givesidxa new value, and Variables shows it.
Running any line in the console removes the error panel. The failing line stays highlighted, and the keys below still work.
The four buttons
- Try Again (Resume) runs the failing line again. Unless a value it uses has changed, the error happens again at once. F5 does the same, and still works after the panel has gone.
- Ignore (Resume Next) skips the failing line and goes on from the statement after it. Here the loop runs to the end, and prints
i = 4, idx = 7, total = 10for the pass that failed. No menu command or key does this. At the panel of a failedDebug.Assertit does nothing. - Stop does not end the program at an error. See Traps.
- Search Online opens a Google search in the default browser. The search text is
twinBASIC VB6, the header and the description of the error.
Note
In twinBASIC BETA 1005, Search Online puts the error text into the address as it is, without encoding it. An & in the description ends the search text at that point, so the search loses the rest, and a " ends the address. Copy the description from the panel and search for it in your browser instead.
Stepping on through the rest of the loop
Step Into (F8 / F11) and Step Over (Shift+F8 / F10) do not move past the failing line. They run it again, and the error happens again at once. To go on one line at a time, first do one of these, then step:
- Correct the value in the console. After
idx = 5, F8 runs the failing line without an error, and stops on the next one,total = total + i. - Move past the line with Set Next Statement. Click in the next line and press Ctrl+F9. The yellow arrow moves there without running the failing line, and the panel closes. F8 then runs the line the arrow is on.
To run on to the end instead, correct the value and press F5, or press Ignore (Resume Next) while the panel is still there.
Editing at the error panel
Edit and Continue is not supported at the error panel either: when you change the code, the console writes [EDIT & CONTINUE] not yet supported. Aborting.. After you change the failing line, F5 starts a new run that runs the changed line.
Warning
In twinBASIC BETA 1005, an edit at the error panel does not abort the program, although the console says Aborting. The rest of the failing procedure is skipped, and the code after its call runs: its output appears in the console, and the run then ends. At a breakpoint the same edit does abort the program. Do not edit the code while the error panel is showing. End the run first, as the Stop warning under Traps describes, and then edit.
Traps
- The panel disappears, and Ignore with it. Running a line in the Debug Console, or clicking another procedure in the Call Stack, removes the panel. F5 brings it back only by running the failing line again. Set Next Statement onto the next line, then F5, does what Ignore (Resume Next) would have done.
Note
In twinBASIC BETA 1005, a step key pressed on the failing line leaves a step waiting. After F8 on the failing line, Ignore (Resume Next) stops again on the next line instead of going on, and the next F5 is used up as well. Press F5 to go on, or use Set Next Statement as above instead of a step key.
Warning
In twinBASIC BETA 1005, Stop at an error ends only the procedure that failed. The procedure that called it goes on from its next line: if Sub Main called FillTable, the rest of Sub Main still runs. The panel’s Stop, the toolbar’s Stop and Run → End all do this. At a failed Debug.Assert, Stop ends only the check, and the test goes on past it as if the check had passed. To end the whole run, first move the arrow to a later line with Ctrl+F9, then press Stop. Away from an error — at a breakpoint, after a step, or after Set Next Statement — Stop ends the run.
See Also
- Running – Start, Break and End, and what ends a run
- Inspecting a paused program – the panels that fill at a stop
- Debug menu – the menu commands of this page
- Testing with Assert – a failed assertion stops the program as an error does