Replace Error Code with Exception
Before you begin: Return values, exceptions, and error handling.
Replace Error Code with Exception reports a failure by raising an exception rather than returning a special value. This separates a successful result from an error that callers might otherwise forget to check. It also changes control flow, so every affected caller needs review. 1
Original version: minus one secretly means failure
A simplified reservation calculation returns the remaining inventory. Inputs are nonnegative counts; a request larger than availability cannot be fulfilled. No shared inventory is modified in this arithmetic example.
public static class Inventory
{
public static int Reserve(int available, int requested)
{
if (requested > available) return -1;
return available - requested;
}
}def reserve(available, requested):
if requested > available:
return -1
return available - requestedA caller forgetting the sentinel check can display “minus one items remaining” or persist the error code as if it were a valid result.
Revised version: failure interrupts the normal result path
public static class Inventory
{
public static int Reserve(int available, int requested)
{
if (requested > available)
{
throw new InvalidOperationException("Insufficient inventory.");
}
return available - requested;
}
}try
{
Console.WriteLine(Inventory.Reserve(1, 2));
}
catch (InvalidOperationException error)
{
Console.WriteLine(error.Message);
}def reserve(available, requested):
if requested > available:
raise RuntimeError("Insufficient inventory.")
return available - requestedtry:
print(reserve(1, 2))
except RuntimeError as error:
print(error)Successful calls still return the remaining count. A failed call no longer produces a value that looks numeric and successful.
Choose the error representation to fit the operation
An expected shortage may be better represented by a typed result, a TryReserve operation, or a domain-specific exception, depending on the application’s conventions. Exceptions are not automatically superior for every ordinary negative outcome.
The migration must preserve user-visible failure handling intentionally. Callers that checked -1 must now handle the exception at an appropriate boundary. Broadly catching everything and returning zero would recreate ambiguity rather than solve it.
This example is not a concurrent reservation system: checking availability and updating real stock would need atomicity. Changing the error-reporting mechanism does not make a check-then-update sequence race-free.