Chapter 8: Error Handling and Debugging
Good error handling lets your program deal with unexpected situations gracefully, and debugging helps you find and fix problems in your code. This chapter covers techniques and tools for both in Pascal.
Runtime errors
Runtime errors happen while the program is running. Division by zero, a missing file, and invalid input are common examples, and Pascal gives you ways to handle them.
Using the try...except block
A try...except block handles exceptions (errors) that occur while the program runs.
In Free Pascal, exceptions need two things at the top of the program. {$mode objfpc} (or {$mode delphi}) turns on the try, except, finally, and raise keywords, which the default mode doesn’t have. uses SysUtils brings in the exception classes, such as EDivByZero, and makes runtime errors like a division by zero raise them as exceptions. Every example in this chapter that uses try starts with both.
Example
{$mode objfpc}{$H+}
program TryExceptExample;
uses
SysUtils;
var
x, y, z: integer;
begin
x := 10;
y := 0;
try
z := x div y;
writeln('Result: ', z);
except
on E: EDivByZero do
writeln('Error: Division by zero');
end;
end.
The try...except block catches the division by zero error and displays a custom error message.
Using the try...finally block
A try...finally block makes sure certain code runs whether or not an exception occurs. It’s often used to clean up resources.
Example
{$mode objfpc}{$H+}
program TryFinallyExample;
uses
SysUtils;
var
fileVar: text;
begin
assign(fileVar, 'output.txt');
rewrite(fileVar);
try
writeln(fileVar, 'Hello, World!');
finally
close(fileVar);
end;
end.
The file is closed even if an error occurs while writing to it.
Compile-time errors
The compiler detects compile-time errors before the program runs. They include syntax errors, type mismatches, and undeclared variables. To fix them, read the compiler’s error messages carefully and correct the problems in your code.
Common compile-time errors
- Syntax errors break the rules of the language’s syntax, for example a missing semicolon (
;) or a misspelled keyword. - Type mismatches mix incompatible data types, such as assigning a string value to an integer variable.
- Undeclared variables are variables used without being declared first.
Debugging techniques
Debugging is the process of finding and fixing errors in your code. Pascal gives you several techniques and tools for it.
Using Writeln for debugging
The simplest way to debug a Pascal program is to add writeln statements that print variable values and show the flow of execution.
Example
program DebuggingExample;
var
x, y, z: integer;
begin
x := 10;
y := 5;
writeln('x = ', x);
writeln('y = ', y);
z := x + y;
writeln('z = x + y = ', z);
z := x div y;
writeln('z = x div y = ', z);
end.
Using the debugger
Many Pascal IDEs, Lazarus among them, have a built-in debugger for setting breakpoints, stepping through code, and inspecting variable values.
Setting breakpoints
A breakpoint is a marker you set in your code to pause execution at that point. While the program is paused, you can examine its state and see how it behaves.
- Open your Pascal IDE (for example, Lazarus).
- Open your Pascal source file.
- Click in the left margin next to the line where you want to set a breakpoint.
- Run your program in debug mode.
Stepping through code
Stepping through code runs your program one line at a time, so you can follow the flow of execution and find the exact point where an error occurs.
- Set a breakpoint as described above.
- Run your program in debug mode.
- Use the “Step Over” or “Step Into” commands to run your code line by line.
Inspecting variables
While debugging, you can inspect the values of variables at different points in your program to check that they’re being updated correctly.
- Pause your program at a breakpoint.
- Hover over a variable to see its current value.
- Use the “Watch” window to monitor specific variables.
Handling specific exceptions
The SysUtils unit defines several exception types that your code can handle. Common ones include:
EConvertError, raised when a string-to-number conversion fails.EInOutError, for errors during input/output operations (a file that can’t be found, for example).EOutOfMemory, which means the system has run out of memory.
Example: handling multiple exceptions
{$mode objfpc}{$H+}
program MultipleExceptionsExample;
uses
SysUtils;
var
x: integer;
str: string;
begin
str := 'abc';
try
x := StrToInt(str);
writeln('Converted value: ', x);
except
on E: EConvertError do
writeln('Error: Invalid number format');
on E: EOutOfMemory do
writeln('Error: Out of memory');
else
writeln('An unknown error occurred');
end;
end.
Converting a non-numeric string to an integer raises EConvertError, and the first handler catches it.