Insights derived from a talk given by Timur Doumler
Key Takeaways
- C++26 introduces contract assertions, a language-level feature for expressing correctness conditions directly in code.
- Contract assertions replace traditional macros with structured, configurable and scalable assertions that integrate properly with the rest of the language.
- Developers can define preconditions and postconditions at the interface level, not just in implementation.
- Assertions can be enabled, disabled and configured without changing code, preserving performance flexibility.
- This is especially critical in finance, where systems must balance low latency with strict correctness guarantees.
Why Correctness Is as Critical as Performance
Performance-critical trading systems are known to focus on speed and latency. However, correctness is just as important: Incorrect behavior in production systems can lead to significant financial loss or market disruption. To improve code correctness at scale, developers need to define what “correct” means in a way that compilers, static analysis tools, IDEs and LLMs can consume. Historically, this has been difficult.
The Limits of Traditional Assertions
Most codebases rely on some form of assertions, typically implemented as macros (either C assert or custom variants). They can be enabled, disabled and configured via the preprocessor. This approach has disadvantages: It can break parsing or introduce ODR violations. And it doesn’t scale well across large, heterogeneous systems.
Moreover, assertion macros must be placed inside function implementations — which may not be accessible by other parts of the system — and thus do not provide a way to express intent on interfaces.
What C++26 Introduces: Contract Assertions
C++26 introduces contract assertions as a built-in language feature. Unlike traditional assertions, they are part of the core language, not macros. As such, they work seamlessly across translation units, modules and large code bases.
At a basic level, contract assertions allow developers to:
- Check that a correctness condition holds at runtime.
- Define how violations of these conditions are handled.
- Configure behavior without changing source code.
Configurable Behavior Without Code Changes
One of the most important improvements is flexibility. Contract assertions support multiple evaluation semantics:
- Ignore: Skip checks entirely.
- Observe: Check and handle violations.
- Enforce: Check, handle and terminate on failure.
- Quick-enforce: Check and terminate immediately without additional handling.
Each evaluation semantic serves a particular use case:
- Ignore emphasizes performance: An ignored assertion has zero runtime overhead.
- Observe allows detection and reporting of bugs in legacy code without the risk of bringing down a working production system.
- Enforce is the recommended default: It prevents a program from continuing past a contract violation, while providing the developer with the maximum amount of information about the bug.
- Quick-enforce is best suited for constrained systems and security-critical applications that must minimize binary size and/or attack surface.
Custom Handling of Failures
C++26 also introduces a contract-violation-handler, which is called when a contract assertion fails. It can be replaced at link time.
This allows developers to define what happens when a contract fails. That can include logging diagnostics and stack traces, triggering debugging workflows or performing a managed shutdown or recovery.
The system provides structured, programmatically accessible information about which assertion failed, where and in what context, aiding debugging and diagnostics.
Preconditions and Postconditions at the Interface Level
The most significant shift, compared to pre-C++26 macro-based assertions, is where the assertions live.
C++26 allows developers to define:
- Precondition assertions: What must be true when a function is called.
- Postcondition assertions: What must be true when the function returns.
These are attached directly to function declarations, not buried inside implementations.
Why This Matters
Contracts become part of the interface and are visible to developers, compilers, IDEs, static analysis tools and LLMs.
This enables earlier, more reliable detection of incorrect usage, better tooling support and clearer documentation of system behavior.
The benefits of precondition and postcondition assertions on declarations are especially important in environments where:
- Systems are composed of many components.
- Teams work across shared interfaces.
- Not all code is visible to all developers.
Contract assertions provide a way to enforce expectations on correctness without exposing internals. This is especially important in finance, where information boundaries matter.
Designed for Incremental Adoption
C++26 contracts are designed to work in real-world codebases. They can be added to existing systems without breaking behavior, and they don’t change the meaning of correct programs. They can also be introduced incrementally, component by component.
This makes adoption practical, even in the large, complex and mature production systems found throughout finance and trading.
The Bottom Line
- C++26 introduces contract assertions as a first-class way to express expectations on code correctness. It replaces macro-based assertions with a structured, scalable language feature.
- Integration with the rest of the language removes numerous limitations. Contract assertions work seamlessly with modules, and they don’t cause ODR violations when different translation units are compiled with different checking modes.
- Developers gain fine-grained control over when and how to check assertions, enforce correctness conditions and handle violations.
- Precondition and postcondition assertions enable the expression of correctness conditions on function interfaces, allowing humans, tooling and LLMs to find bugs in C++ code earlier and more effectively.