Handling Errors Gracefully in Programs
A program is correct when it accomplishes the task it was designed to perform, and this is judged against the inputs it is meant to handle.
Why a Crash Is Not Automatically a Bug
When a program crashes, it is tempting to conclude that the program is wrong. The reasoning seems simple: if the program stops with an error, it must have failed, and if it stays calm and produces a neat result every time, it must be doing its job. This instinct feels reasonable, but it merges two separate questions that programmers need to keep apart. The first question is whether a program does its job. The second is whether it survives situations it was not meant to face. A program can answer yes to the first and no to the second, and the difference matters when you decide how to build and judge software.
The two ideas that this article separates are called correctness and robustness. Both are ways of evaluating a program, but they measure different things. The sections that follow start with a concrete program, make you predict how it should be judged, and then build the definitions from that example.
Predicting How a Sorting Program Should Be Judged
Imagine a program whose job is to read a list of numbers from the user and print them in sorted order. Suppose that for every valid list of numbers it sorts correctly. But when the user types a word such as seven instead of a number, the program stops with an error and quits. Before reading on, decide on two answers: would you call this program correct, and would you call it robust?
What do you think happens?
Is the sorting program correct, and is it robust?
Reveal answer
Correct but not robust
The program does its designed task, sorting numbers, for every valid list it is given, so it is correct. Crashing on the word seven is a failure to handle illegal input gracefully, which is a robustness failure. The crash tells you about robustness and says little by itself about whether the program does its job.
What Correctness Means
A program is correct when it accomplishes the task it was designed to perform, and this is judged against the inputs it is meant to handle.
The key phrase is judged against the inputs it is meant to handle. Correctness is not measured against every imaginable input. It is measured against the inputs the program is supposed to accept. For the sorting program, the designed task is to read numbers and print them in sorted order. For that program to be correct, it has to produce sorted output for any set of input numbers. A single set of numbers that comes out unsorted is enough to show that the program fails its task.
Tracing the Sorting Program on Valid Input
Checking whether the sorting program is correct
The program reads a list of numbers from the user and prints them in sorted order. Is it correct for the input 4, 1, 9?
- 1Identify the designed task
The task is to read numbers and print them in sorted order.
- 2Identify the inputs the program is meant to handle
The inputs are lists of numbers, so 4, 1, 9 is a valid input in the expected range.
- 3Compare the output with the task
The sorted output is 1, 4, 9. This matches the designed task.
- 4Decide on correctness for this input
This input is handled correctly. To show the program is correct in general, the same check must succeed for any set of valid numbers. One unsorted output would be enough to show it is not correct.
For valid input, the output matches the designed task, so the program is behaving correctly on this case.
What Robustness Means
A program is robust when it handles illegal inputs and unexpected situations in a reasonable way, such as reporting an error and ignoring bad input rather than crashing.
Robustness is judged against different conditions than correctness. Correctness is tested with the inputs the program is supposed to handle, and asks whether it reaches its goal. Robustness is tested with inputs outside that expected range, and asks whether the program fails gracefully. Because the conditions differ, a program can pass one test and fail the other.
The standard for robustness is reasonableness, not perfection. The sorting program does not need to guess what the user meant by the word seven, and it does not need to recover every possible value. It needs to avoid a crash or nonsensical output, and to respond in a way a sensible person would consider acceptable. The source contrasts a robust response, which prints an error message and ignores the bad input, with a non-robust program that might crash or give nonsensical output when it meets the same bad input.
How a Bad Input Travels Through a Program
The flowchart below follows a single item of input through the sorting program. The key question is what happens at the decision point: when the input is illegal, does the program reject it, recover, or crash? A robust program sends illegal input down a path that reports the problem and continues. A non-robust program has no such path, so the bad input falls through to a failure.
The flowchart has two branches for illegal input. The robust branch reports the error and ignores the bad input, so the program keeps going and can still produce a sorted result from the valid items. The non-robust branch ends in a crash. Both programs can be correct on valid lists; the only difference is what they do on the illegal path.
Error: ignored non-numeric input: seven
[1, 4]int(item)raisesValueErrorwhen the item is not a number such as seven- The except branch is the robust path: it reports the error and skips the bad item
- The valid items are still sorted, so the program continues to do its task
Graceful Handling Between User and Program
Graceful handling is easiest to see as a sequence of exchanges. The user supplies input, the program detects that the input is illegal, an error handling step produces a message, and the program continues rather than stopping. The diagram shows the order in which these three parties exchange input, failure, and message.
The error message is part of the robust response. The source describes a program that prints an error message and ignores the bad input. The message tells the user what went wrong, and the program does not depend on guessing what the user meant. The purpose is a reasonable reaction, not a perfect interpretation of every mistake.
Correctness Versus Robustness Side by Side
The two properties are easiest to tell apart by comparing two programs, each of which has one property without the other. The first program is correct but not robust, like the sorting program that crashes on seven. The second is robust but not correct: it prints a friendly error message for every input, including valid lists, and never sorts anything. Its handling of bad input looks polite, but it fails its designed task.
| Property | Measured against | Valid input | Illegal input | Question it answers |
|---|---|---|---|---|
| Correctness | The inputs the program is meant to handle | Produces the required result | Not the main test | Does the program do its job? |
| Robustness | Inputs outside the expected range | Not the main test | Reports the error and continues | Does the program fail gracefully? |
| Correct but not robust | Valid lists sorted properly | Sorted output | Crashes | Does its job, but fails on bad input |
| Robust but not correct | Error messages for bad input | Wrong or missing result | Reports the error and continues | Handles bad input politely but fails its task |
Correctness and robustness are judged against different conditions, so a program can have one property without the other.
Deciding How Much Robustness Is Enough
The source makes a clear distinction here. Every program should be correct. Not every program needs to be completely robust. Whether a program needs more robustness depends on who will use it and how it will be used. Robustness is a design decision about how much care the situation deserves, not a checkbox every program must tick.
Mistakes About Crashes and Correctness
Common mistake Treating any crash as proof that the program is incorrect
What it looks likeThe sorting program stops with an error when the user types seven, and someone concludes it does not sort correctly.
Why it failsA crash on illegal input is evidence about robustness. The program may still sort every valid list correctly.
Do this insteadAsk separately whether the program does its designed task on valid inputs, and whether it handles illegal inputs reasonably.
Common mistake Treating a calm, neat output as proof that the program is correct
What it looks likeA program prints a polite error message for every input, including valid lists, and is judged correct because it never crashes.
Why it failsCorrectness is about accomplishing the designed task. A program that never sorts anything is not correct, even if it is polite.
Do this insteadCheck the output for valid inputs against the designed task before judging correctness.
Common mistake Demanding full robustness from every program
Why it failsThe source states that not every program needs to be completely robust, and the required level depends on who uses it and how.
Common mistake Assuming a robust program must recover every possible value rather than respond reasonably
Testing Your Judgment on a New Program
A program is designed to read a temperature in degrees Celsius and print the matching Fahrenheit value. For valid numbers it prints correct conversions. When the user types hot, it prints an error message and asks again. Decide whether the program is correct, whether it is robust, and how much robustness it needs if it is only used by you on your own computer. Explain each answer using the definitions in this article.
Hints
- Start by naming the designed task and the inputs the program is meant to handle.
- Judge correctness with valid numbers, and judge robustness with the word hot.
- Ask who will use the program and what happens if it fails for that user.
Key Takeaways
- A program is correct when it accomplishes the task it was designed to perform, judged against the inputs it is meant to handle.
- A program is robust when it handles illegal or unexpected input reasonably, such as reporting an error and ignoring bad input rather than crashing.
- Correctness and robustness are separate properties, so a program can be correct without being robust, and a crash on bad input says little by itself about whether the program does its job.
- Every program should be correct, but the required level of robustness depends on who will use the program and how.