I'm trying to understand the purpose of assertions. They're often described as checks for conditions that must always be true, but an if/else statement or an exception can also detect a false condition. If the result is similar, what problem do assertions solve? How are they different from normal control flow, exception handling, and automated tests? I'd also like to understand where the idea came from and why assertions were introduced instead of relying solely on if/else logic.
5 Answers
A useful rule of thumb is:
- Use if/else when different outcomes are normal and the program should choose what to do next.
- Use exceptions when an unusual runtime problem occurs and some higher-level code may recover, report it, or clean up.
- Use assertions when continuing would be unsafe or misleading because an internal assumption has been violated.
- Use automated tests to exercise expected scenarios and verify behavior from outside the implementation.
The exact practice depends on the language and the system. High-availability software may log and recover instead of crashing, while a development build may deliberately fail fast. The important distinction is whether the condition is an expected runtime case or evidence that the program itself is broken.
The key difference is intent. Use if/else or exceptions for situations your program is expected to encounter and should handle, such as invalid user input, a missing file, or a network timeout. Use an assertion for a condition that should be impossible if your own code is correct. If it fails, it usually means there’s a programming bug or an invalid internal state, so stopping immediately can expose the problem before it causes more damage.
For example, a queue can legitimately be empty, so that should be handled with normal logic. But if the queue’s internal pointers violate their required relationship, that indicates a broken invariant and is a good candidate for an assertion.
Assertions, exceptions, and automated tests operate at different levels. A test is a separate piece of code that runs a scenario and verifies the result. An assertion is a check placed inside the implementation to verify an invariant or assumption while that implementation runs. Tests can prove that certain cases work, but assertions can still catch unexpected states caused by future changes or unusual execution paths.
A failed assertion generally means “the program has entered a state we didn’t design for.” An exception generally means “something went wrong, but this is a runtime problem the caller may be able to handle.” Some projects use assertions only in tests or debug builds, while others retain carefully chosen internal assertions in production for diagnostics or safety.
Assertions are also executable documentation. Something like `assert result.length == input.length` tells future maintainers that the function promises to preserve the number of elements. Unlike an ordinary comment, the assertion actively checks that assumption during development and testing.
Many languages let you disable assertions in optimized or production builds. That makes them useful for catching internal mistakes without necessarily adding runtime cost. Don’t use them for input validation, authentication, permissions, or anything the program must enforce in production, because disabled assertions would remove that protection.
The idea is closely associated with formal reasoning about programs and design by contract. A function can have preconditions that callers must satisfy, postconditions it promises to establish, and invariants that must remain true throughout its operation. Assertions provide a concise way to state and check those contracts.
The concept predates modern exception systems and was popularized through work such as Hoare logic and the design-by-contract approach. Assertions weren’t created because if/else statements were incapable of checking conditions; they were created to communicate that a condition is a programmer-level guarantee, not an ordinary branch of application behavior.

So an assertion is mainly checking assumptions made by the programmer, while input validation is part of the program’s normal behavior?