Hello
Sharing my notes and feedback after reading.
I read P4334R0:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4334r0.pdf
Is it possible to review/reconsider P2900 until this approach for Contracts have had more time for field use?
BTW, there is also a broken (404) link in P4334R0 to D4324R0:
https://isocpp.org/files/papers/D4324R0.html
Could someone point me to the paper?
I read P4332R0 too
https://isocpp.org/files/papers/P4332R0.html
I have some concerns about C++ Contracts.
Please do try it out. It's available on any machine that can install GCC16. There is also a Clang fork that implements most of it, that is not merged to mainline but that is being actively worked on in two directions - one to extend it, and one to merge it to main.
One of the papers says it's not implemented - I don't understand how they cannot see GCC16 existing since March, in a paper written in August. It makes you doubt the other statements in the paper, even though there are some valid concerns in there.
With regards to actual use of it, many people I talk to are indeed trying it out, and finding it very useful. Quoting from two people's unprompted statements:
> Once you set up the initial callback function the syntax around it seems to be really quite simple > They really are. I'm finding they're bloody useful.
I have been looking into the quality of implementation, and there are a few bugfixes pending on GCC still.
I have also looked at what constification would mean for an actual codebase in P3268, and tried it in my personal codebase of about 50kloc, where it found one ICE in both the GCC and Clang implementations (Clang is unmerged), and about 10 bugs in my code. Not a widespread rollout, true, but experience nevertheless. That specific ICE was fixed this week for a future release.
We can postpone contracts until after more experience is gained, but that does cause issues for further development on contracts, and on anything else that tries to rely on their specification for runtime checks and failure handling. Nothing insurmountable, but unpleasant nonetheless.
At a conceptual level, contracts are Hoare logic: precondition, command, postcondition. That underlying idea is simple, whereas the C++ Contracts specification appears far more complicated.
If there was scope to consider a simpler approach, which places emphasis on compile-time checks that would be very useful for functional safety. Runtime checks are risky.
Relying upon a contract violation being detected at runtime has issues. The violation may occur only after deployment, and runtime checks may potentially be marked 'ignore'. The contract-violation handler also introduces a runtime path which cannot necessarily be shown at compile time to be unreachable. For functional safety, it's an unknown, if it will be called.
This is relevant to functional-safety software, where it is important to demonstrate that a violation handler cannot be called, rather than relying on it to catch a violation at runtime. Which leaves the question what to do, when it is called. Hard to prove, if the symbol is present and linked to.
My own proposal, compile_assert(), P4021, explores a different approach:
https://wg21.link/P4021
compile_assert() operates at compile time and deliberately has a very small implementation model. Naturally, it can only verify properties which the compiler is able to determine at compile time.
As an experiment, I have implemented contract-like checks in terms of compile_assert().
https://github.com/jonnygrant/compile_assert/blob/main/testsuite/main28_a.cpp
compile_assert, if I understand it correctly, is identical to contracts in P2900 when set up to have a C++ library that does not implement its violation handler function. Your program will link if and only if it could be proven during compilation. That already works like that - in fact, I at first didn't notice I had forgotten to switch over to my experimental libc++ until it failed to link after adding a few contracts. The first few in the places they were called were always true and didn't emit a symbol to link to in the first place.
With regards to proving things at compile time, the current definition of contracts is enough for simple assertions. Anything that is too complicated (lamdbas, usually) or that passes through an opaque interface that the compiler cannot see into, cannot be optimized. In particular, a sequence f(g(x)) where both g(x) has a postcondition r:p(rv) and f(r) has a precondition p(r), cannot forward the result of a postcondition on g(x) to f, as there is no way to explain that evaluating p with the same argument twice will do the same thing twice. For repeated checks on a precondition we have taken that allowance into the standard, but for this specific situation we'd need something like [[reproducible]] or [[unsequenced]] as in C.
Beyond that, I know that multiple different groups of people are looking into what specifically we can do with contracts as specified, and what we'd need to change or add. So far the results seem to be that it works well enough, but that with minor tweaks we can make it more powerful. A hypothetical [[mustprove]] attribute could exist in a compiler, requesting it to fail the build if it cannot prove a functions' calls' pre-contracts, and its postcontract, based on its own pre-contracts and its calls' postcontracts. Basically, asking the compiler to do the Hoare propagation and seeing if it connects, at a semantic level that would need to be done early on in a compiler. Given such information, depending on build modes, a compiler can just remove all checks in that function, as there's no way they don't hold. Will never be able to do all code - but if it can do 95% of the code, I'll happily review or rewrite the remaining 5%. Think of it like a borrow checker for the guarantees that brings, except functional safety (and whatever memory safety was expressed in contracts).
But let's first see what happens with the C++26 DIS. If you want to form an opinion on how well it works, try it out - godbolt, local install - and form your own opinion. And if you'd like it to have more features maybe consider not voting against for that reason. That's not going to get you more features - it's only going to cause more turbulence and delay.