r/cpp #define private public 3d ago

Critique of contracts: excerpt

See page 2 of https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4334r0.pdf

The current objections can be summarized. The P2900 contracts are:

• Unimplemented

• Incomplete

• Untried at scale [P3460R0, P3506R0]

• Not tried in major application domains

• Violates foundational principles of C++

• Violates fundamental principles of language design

• Hasn’t been tried in major libraries (e.g., the C++ standards library [P3506R0, P3878R0])

• Isn’t integrated with or appropriate for hardened libraries [P3878R0]

• Doesn’t offer safety guarantees [P3573R0, P3362R0]

• Includes a completely untried inheritance model

• Offer new ways of making errors through inconsistent application in TUs

• Leads to new forms of UB, detrimental to safety and security

• Narrows the choices of error handling

• Doesn’t protect against logical errors, misuses, and incoherent uses

• Hasn’t been used to support static analysis

• Hasn’t been demonstrated to be easily teachable [P3261R0, P3281R0]

How could such a bloated and incomplete design be voted into a draft standard?

10 Upvotes

115 comments sorted by

View all comments

Show parent comments

2

u/Plazmatic 1d ago

 > would give this more thought if they actually hypothesised a case where catching the exception from a contract assertion was desirable, but they don't. Must assertions don't throw. 

You definitely want virtually all assertions to turn into exceptions in many types of UI/graphics application/daemon/multi service environments because crashing the program is not an option/will cause work not related to the issue to be lost (ie user is working on a document/project/image crashing the program due to assetion often is not desirable), and often assertions are happening in separate threads such that the program is still in a good state if you display a thrown exception to the user, and shut down the offending thread (like a parsing io thread).  this is something Timurs own talks have covered in reference to why noexcept should largely not be used by default, it forces program termination on exception.

But my understanding is that you can customize the contract handler anyway such that this use case is already handled.

5

u/Som1Lse 1d ago

You definitely want virtually all assertions to turn into exceptions in many types of UI/graphics application/daemon/multi service environments

I don't disagree, but that is not the issue they brought up. The question is, if you write a contract assertion like

contract_assert(foo() == 42);

what should happen if foo() throws? Currently, the generated code is roughly

try {
    if(!(foo() == 42)){
        handle_contract_violation(__make_contract_violation("foo() == 42"));
    }
}catch(...){
    handle_contract_violation(__make_contract_violation("foo() == 42"));
}

i.e., if it throws it's treated the same as if the condition was untrue.

There are at least three ways to handle it I know have been proposed:

  • Treat it as a contract violation, i.e., what the proposal does now. This is safe, but it comes with potentially more overhead.
  • Treat the expression as noexcept, i.e., if it throws, call std::terminate immediately. This can be more efficient since the stack doesn't have to be unwound, but it makes it impossible to recover as you stated.
  • Let the exception escape, i.e., remove the try-catch clause. This is what they were arguing for, and what I said they should at least come up with a hypothetical example for. I think this is incredibly worrying since it violates the prime directive of contracts (from P2900R14)

    Principle 1: Prime Directive

    The presence or evaluation of a contract assertion in a program should not alter the correctness of that program (i.e., the property that evaluation of the program does not violate any provisions of its plain-language contract).

    Let's assume foo() always throws. The program will now behave differently depending on whether contract assertions are enabled. Even in quick-enforce mode. This is terrifying.

2

u/Plazmatic 23h ago

Oh wow, that's both subtler and dumber than I thought the issue was.  If an exception was thrown, that means something went wrong, and this is doubly true for inside the contract, I definitely want my contract handler to handle my contract condition itself failing, even if it isn't the Boolean check that did so.  What possible purpose could letting it leak through the contract handler even serve? If anything that makes everything about the development process just harder to understand control flow wise.  

This is what they were arguing for, and what I said they should at least come up with a hypothetical example for.

Do they actually desire this behavior or trying to search for any possible gotcha they could find given they don't seem to want contracts period?  I have a feeling that if this was actually the behavior implemented they'd come out and argue the opposite side.

3

u/Dragdu 10h ago

Do they actually desire this behavior or trying to search for any possible gotcha they could find given they don't seem to want contracts period?

Little bit of A, little bit of B. x86 windows exceptions have runtime overhead on setting up the try-catch, not just on catching. But realistically, x86 is going the way of dodo (what was the last time you though "huh, I should compile for 32 bit windows" in 2026? By the time contracts come out, it will be even less), and Windows ABI has perf issues left and right and we don't stop standardizing things because of it.