On Contracts and Safety -- Lucian Radu Teodorescu
Composing safe functions may not be safe. Lucian Radu Teodorescu explores how C++26 contracts help uncover problems.
On Contracts and Safety
by Lucian Radu Teodorescu
From the article:
If two operations are safe, is their composition safe too? At first glance, the answer ought to be yes. But a small expression such as
f(g(10))can appear to contradict that intuition: both functions may be safe under their own contracts, while the nested call still violates memory safety. The missing piece is the caller. Safety does not compose merely because expressions are nested; it composes when obligations and guarantees line up at each boundary.Building on the previous article [Teodorescu26], this article looks at how contracts help us build safe programs. Contracts give us a structured way to describe obligations and guarantees, both at software boundaries and inside implementations. In that context, we briefly describe C++26 contracts.
We then look more closely at a common source of confusion around the composability of safety. We also consider enforced safe operations as a practical way to build safe programs with respect to selected safety properties. Finally, we look at documentation contracts as a complementary way to express contracts that do not belong in code. Both forms help build safety into applications.
Contracts
‘Design by Contract’ is the discipline of making the obligations and guarantees of software components explicit [Meyer91]. A routine may impose preconditions on its callers, promise postconditions on return, and preserve invariants associated with the object or module it belongs to. The main point is not just that these predicates may be checked, but that they make the boundary between client and implementation explicit.
C++26 contracts bring part of this discipline into the language [P2900]. The core idea is that users can add contract assertions to programs, providing machine-checkable statements about expected program behaviour. These contract assertions come in three forms: preconditions, postconditions, and general-purpose assertion statements.