Other than compiler errors, another major type of error is a runtime error. Runtime errors occur when the compiler executes and compiles the program into bytecode properly but the program subsequently fails during the execution of its instructions. Runtime errors are generally more difficult to diagnose than compiler errors for two reasons. First, they often return messages that are indecipherable like "Access violation at address 0xFFAB23D9" or "Illegal operation at address 0xFFAB23D9." You may have seen messages like these in your common day-to-day activities while working on the computer. What they mean is that a runtime error occurred and its location in the compiled bytecode is address 0xFFAB23D9. Fortunately, most modern development environments keep track of which addresses in bytecode correspond to which lines of your code and can jump directly to the location of a runtime error. Unfortunately, the messages are generally so unintelligible that you have to develop an intuition for what went wrong. For example, try running the following code:
{$APPTYPE CONSOLE}
program Workspace;
var
X : Real;
begin
X := 0;
Writeln(10/X);
end.
Depending on the runtime environment, this code may generate an helpful error like "Floating point divide by zero." or an unhelpful one like "External: SIGFPE" (FPE stands for floating point error by the way). The problem here is that we cannot divide by zero. The compiler does not catch this because it is neither a syntax or semantic error. A very high quality compiler could have figured out that X would contain 0 when 10/X was executed, but few actually do. When a runtime error occurs you either need to press Ctrl+F9 (to force a compile and abort the program) or press the red stop square button if you are using Lazarus.
The first reason that runtime errors are difficult to diagnose is the indecipherable messages. The second is that code is often written in a way that sometimes the program will execute without a runtime error and other times it will fail with a runtime error. Consider the program we wrote previously:
{$APPTYPE CONSOLE}
program Workspace;
var
Dividend,Divisor : Integer;
begin
Writeln('This program will divide two integers.');
Write('Please enter the dividend: ');
Readln(Dividend);
Write('Please enter the divisor: ');
Readln(Divisor);
Writeln(Dividend,' divided by ',Divisor,' equals ',
Dividend div Divisor,' and ',Dividend mod Divisor,'/',Divisor);
Readln;
end.
Run this program and enter 10 as the dividend and 0 as the divisor. The program will throw a runtime error. The program will run perfectly fine if any integer other than 0 is entered as the divisor. This means that for almost all situations the program will appear to be perfectly written. It is only in rare cases that the problem with the code will be apparent. Note also that this program will fail if you enter a decimal number instead of an integer.
The errors that cause programs such as Firefox or Microsoft Word to crash are runtime errors. Though it is the programmer's job to anticipate and "catch" user interactions with the program that will lead to errors, with complex programs it is nearly impossible to anticipate all possible sets of user input that might occur in the program. Thus, rare cases of input can lead to program failure.
Another runtime error could occur from leaving the {$APPTYPE CONSOLE} directive off of a program that uses Writeln or Readln. These two subroutines expect a console window to be open for them to read and write from. If one is not, a runtime error will occur. For example, try running the following:
program Workspace;
begin
Writeln('Trying to write to the nonexistent console.');
end.
The final type of error is a design error. Sometimes a program will compile and run perfectly fine but will not do what the programmer or user intends it to do. For example, consider the following program:
{$APPTYPE CONSOLE}
program Workspace;
var
Dividend,Divisor : Integer;
begin
Writeln('This program will divide two integers.');
Write('Please enter the dividend: ');
Readln(Dividend);
Write('Please enter the divisor: ');
Readln(Divisor);
Writeln(Dividend,' divided by ',Divisor,' equals ',
Dividend mod Divisor,' and ',Dividend div Divisor,'/',Divisor);
Readln;
end.
Here we transposed the location of mod and div in Line 11. If you run this program with dividend 10 and divisor 3 you get "10 divided by 3 equals 1 and 3/3" as output which is obviously wrong. Design errors are often easily found simply by properly testing a program, but diagnosing the problem is generally far more difficult (even worse than a runtime error because no one will tell you what line contains the error). For this reason, modern programming environments have a number of tools to help in diagnosing the problem. We discuss these tools in the next section.