Concepts / Preventing Common Runtime Errors

Preventing Common Runtime Errors

The Guardian Pattern strategically places a guard condition before a risky operation in an 'and' expression to prevent runtime errors.

  • Programming

Why Order Matters

A runtime error can occur when a program attempts an operation that its current data cannot safely support. A common prevention strategy is the Guardian Pattern: place a guard condition before the risky operation in an and expression. The guard checks whether the operation is safe. If the guard is false, short-circuit evaluation stops the expression before the risky operation runs.

In the real world

Imagine checking a denominator before using it in a division calculation. The denominator is the guard target: the calculation should proceed only when the denominator is non-zero. The check must happen before the division, because checking afterward would be too late.

The Guardian Pattern

Definition

The Guardian Pattern strategically places a guard condition before a risky operation in an and expression to prevent runtime errors.

Input valueGuard conditionsafe?Expression stopsRisky operationevaluate firstfalsetrue
How does evaluation stop after the guard is false, preventing the risky operation from running?

The two parts of the expression have different jobs. The guard condition tests whether the data is valid or safe. The risky operation uses that data. Because the guard appears first, a false guard prevents the later operation from running. A true guard allows evaluation to continue to the risky operation.

Worked example

Checking a Denominator Before Division

Construct an and expression that permits a division calculation only when its denominator is non-zero.

  1. 1
    Identify the guard

    The guard checks that the denominator is non-zero.

  2. 2
    Identify the risky operation

    The risky operation is the division calculation that uses the denominator.

  3. 3
    Place the guard first

    Write the non-zero check before the division in the and expression.

  4. 4
    Trace the false case

    If the denominator is zero, the guard is false, so short-circuit evaluation stops before the division is attempted.

  5. 5
    Trace the true case

    If the denominator is non-zero, the guard is true, so evaluation continues to the division.

Result

The guard protects the division because it is evaluated before the operation it protects.

Tracing Evaluation

What do you think happens?

An and expression begins with a guard that is false. Will the later risky operation be evaluated?

  • Yes, every part of the expression is always evaluated

  • No, evaluation stops at the false guard

Reveal answer
Answer:

No, evaluation stops at the false guard.

Short-circuit evaluation stops the expression as soon as a condition is false. Since the guard is first, the later operation is not run.

Evaluation proceeds from the first condition toward the later condition. When the first condition is false, the and expression already cannot succeed, so the remaining operation is unnecessary. This is the control-flow advantage of the Guardian Pattern: invalid data is blocked before it reaches the risky operation.

Guard conditionfirstRisky operationlaterExpression endswhen guard is falsetruefalse
In what order does the program evaluate the guard and the risky operation, and where can evaluation stop?

Ordering Safe Conditions

Condition orderWhat happensProtection
Guard and risky operationThe guard is evaluated first. A false guard stops evaluation before the risky operation.Protects the operation.
Risky operation and guardThe risky operation is reached before the guard can stop it.Does not reliably protect the operation.

A guard protects a risky operation only when the guard comes first.

GuardfirstRisky operationfirstRisky operationlaterGuardlaterif truetoo late
What happens differently when the safe guard is placed before the risky operation versus after it?
  • Identify the operation that could fail with invalid data.
  • Identify the condition that proves the data is safe or valid.
  • Place the guard condition first in the and expression.
  • Check that a false guard prevents evaluation from reaching the risky operation.
  • Allow the operation only when the guard is true.

Common Guard Targets

The specific guard depends on the operation and its data. A non-zero check can guard a division denominator. A valid-index check can guard an array access. A valid-data check can guard a calculation that requires acceptable input values. In each case, the same structure applies: test the data first, then perform the operation only when the test succeeds.

Risky operationGuard conditionPurpose
DivisionDenominator is non-zeroBlocks an unsafe denominator before division.
Array accessIndex is validBlocks an invalid index before access.
Calculation using inputData value is validBlocks unacceptable data before the calculation.

Examples of operations and the guards that can precede them.

Mistakes with Guards

  • Common mistake

    Putting the risky operation before the guard

    What it looks like

    Risky operation and data is valid

    Why it fails

    Evaluation reaches the risky operation before the later condition can prevent it.

    Do this instead

    Place the condition that checks the data before the operation that uses the data.

  • Common mistake

    Assuming that any guard in the expression will provide protection

    What it looks like

    The expression contains a non-zero check, but the division appears first.

    Why it fails

    Guard placement is critical. A guard that comes after the risky operation cannot stop that earlier operation.

    Do this instead

    Trace the expression from left to right and verify that the guard is evaluated first.

  • Common mistake

    Skipping the guard because the input usually looks valid

    What it looks like

    Using a denominator, index, or data value without checking it.

    Why it fails

    Runtime errors can occur when the current value is invalid, even if other values were valid previously.

    Do this instead

    Use the appropriate non-zero, valid-index, or valid-data guard before the operation.

Edge case

A guard protects only the operation that comes after it in the expression. If an expression contains several risky operations, inspect the ordering of each one and confirm that its relevant guard appears before it.

Practice the Pattern

MEDIUM

For each situation, describe the guard condition and state what must appear first in the and expression: a division with a possibly zero denominator, an array access with a possibly invalid index, and a calculation using possibly invalid data.

Hints
  • Name the value that could make the operation unsafe.
  • Write the condition that establishes the value is safe or valid.
  • Place that condition before the operation that uses the value.
Worked example

Diagnosing a Failed Guard

An expression is intended to prevent an invalid array access, but the array access is written before the index-validity check. Does the guard protect the access?

  1. 1
    Locate the risky operation

    The array access is the operation that may fail when the index is invalid.

  2. 2
    Locate the guard

    The index-validity check is the guard.

  3. 3
    Compare their order

    The risky access appears first, while the guard appears later.

  4. 4
    Apply short-circuit reasoning

    The later guard cannot stop an operation that has already been reached.

Result

The guard does not protect the array access. Move the index-validity check before the access.

Key Takeaways

  1. 1
    The Guardian Pattern places a guard condition before a risky operation in an and expression.
  2. 2
    Short-circuit evaluation stops when a condition is false, so later operations are not run.
  3. 3
    Condition order is essential: the guard must come before the operation it protects.
  4. 4
    Useful guards check non-zero denominators, valid array indices, and valid data values.
  5. 5
    To design a guard, identify the risk, define the safety check, place the check first, and trace the false case.

At a glance

  • Use the Guardian Pattern to check data before a risky operation.
  • Rely on short-circuit evaluation to stop an and expression when the guard is false.
  • Place every guard before the operation it protects.
  • Check denominators, array indices, and data values before using them.

Related concepts

More concepts starting with P