Exceptions or return values: rethinking error handling
Error handling is one of the most misused aspects of programming. Separating the exceptional from the normal changes a lot.
1 min read
Error handling is probably one of the most misused aspects of programming. There are generally two approaches: throwing exceptions, or returning errors through return values.
A simple but fundamental distinction
In languages that lean heavily on exceptions, experience and readings like Code Complete led me to a simple rule:
- Exceptions should be reserved for genuinely exceptional situations.
- Functional errors should be handled through return values.
A validation error — an invalid postal code, say — is not exceptional. It’s a normal scenario in the business domain. Using an exception there breaks the normal flow of the program, and it’s rarely efficient.
Conversely, an unavailable database, a network outage or data corruption: that’s where we’re truly in exceptional territory.
The Go approach
The Go language takes a different stance: no exceptions, every error is a returned value.
res, msg, err := computeAndMessage(a, b)
if err != nil {
fmt.Println("Error detected:", err)
}
It’s more verbose, yes. But also more explicit and simpler. Above all, it forces you to treat every error as part of the program’s normal flow. Another advantage: the ability to return multiple values, which makes handling the error alongside the result feel natural.
It’s not a universal solution, but an approach worth considering — especially in architecture.