Error Handling Strategies
The Guardian Pattern strategically places a guard condition before a risky operation in an 'and' expression to prevent runtime errors.
Preventing the Failure
A runtime error can occur when a program performs an operation before confirming that the operation is safe. The Guardian Pattern addresses this by placing a guard condition before the risky operation in an and expression. If the guard is false, short-circuit evaluation stops the expression, so the later operation is not run.
Following the Short-Circuit Path
The Guardian Pattern depends on short-circuit evaluation. The expression checks the guard first. When that condition is false, evaluation stops immediately. Because evaluation stops, the subsequent risky operation is prevented from running. When the guard is true, evaluation can continue to the operation that follows it.
What do you think happens?
Suppose an and expression checks whether a denominator is non-zero before using that denominator in a calculation. What should happen when the denominator is zero?
Reveal answer
Answer: The guard becomes false and the later operation is skipped.
Short-circuit evaluation stops the expression as soon as a condition is false, so the later operation is not run.
A Guarded Calculation
Checking a Denominator Before Use
Construct an and expression that uses a denominator only after checking that it is non-zero.
Name the risk: The risky part is the calculation that uses the denominator.
Create the guard: Use a condition that checks whether the denominator is non-zero.
Place the guard first: Put the non-zero check before the calculation in the and expression.
Follow the false path: If the denominator is zero, the guard is false, short-circuit evaluation stops, and the calculation is not evaluated.
Follow the true path: If the denominator is non-zero, the guard is true, so evaluation may continue to the calculation.
The guarded expression protects the calculation because the condition that establishes safety appears before the operation that depends on it.
The important feature of this example is not the particular calculation. It is the dependency order: first establish that the denominator is safe, then allow the calculation that uses it to be considered. The guard is useful because it controls whether the risky operation is reached.
Ordering the Conditions
In a guarded logical expression, the conditions are not interchangeable. The guard must appear before the operation it protects. This ordering allows a false guard to stop evaluation before the risky operation is reached. If the risky operation appears first, it may be evaluated before the program checks the condition intended to protect it.
| Condition order | What happens when the guard is false | Protection |
|---|---|---|
| Guard, then risky operation | Short-circuit evaluation can stop before the risky operation | The intended Guardian Pattern |
| Risky operation, then guard | The risky operation may already have been evaluated | The guard may fail to protect the operation |
When Protection Fails
Putting the guard after the risky operation
Short-circuit evaluation can stop only at the point where a false condition is encountered. A later guard cannot undo an operation that has already been evaluated.
Fix:
Move the guard before the risky operation.Treating condition order as unimportant
The Guardian Pattern relies on the guard being evaluated first.
Fix:
Identify the operation that could cause a runtime error, then place its safety check before it.Using a guard that does not establish the needed safety
A condition protects an operation only when it checks the relevant safety requirement.
Fix:
Match the guard to the risk: check for a non-zero denominator before using it, a valid array index before accessing an array position, or valid data before using that data in a calculation.
Building the Expression
- Identify the operation that could produce a runtime error.
- Determine the condition that would make that operation safe.
- Place the safety condition first in the and expression.
- Place the risky operation after the guard.
- Trace the false-guard path and confirm that short-circuit evaluation stops before the risky operation.
- Trace the true-guard path and confirm that evaluation can continue to the operation.
The reusable structure is: relevant safety check, then and, then dependent operation. The safety check comes first because a false result must be able to stop evaluation before the dependent operation runs.
Practice the Guard
For each situation, identify the guard and the risky operation, then describe their correct order in an and expression: a calculation involving a denominator, an access using an array index, and a calculation using data whose validity has not yet been confirmed.
Hints
- The guard should state the safety condition relevant to the risk.
- Place the guard before the operation it protects.
- Ask what must be true before the operation can safely be considered.
A strong answer should name both parts of each pair. For the denominator case, the guard checks for a non-zero denominator. For the array case, the guard checks for a valid index. For the data case, the guard checks that the data is valid. In every case, the guard comes before the operation that uses the value.
Key Takeaways
- The Guardian Pattern places a guard condition before a risky operation in an and expression.
- Short-circuit evaluation stops the expression when a condition is false.
- A guard can prevent a later operation from running and thereby prevent a runtime error.
- Condition order is essential: the guard must come before the operation it protects.
- Useful guards check non-zero denominators, valid array indices, and valid data values.
Key Takeaways
- The Guardian Pattern uses a safety condition before a risky operation.
- Short-circuit evaluation prevents later operations from running when an earlier condition is false.
- A guard fails to protect code when the risky operation is placed before the guard.
- To construct a guarded expression, identify the risk, write its relevant safety check, and place that check first.