logoalt Hacker News

C++26 Contracts: Introduction to Preconditions and Postconditions

117 points • by ibobev • today at 1:11 PM • 110 comments • view on HN

Comments

cogman10 • today at 2:34 PM

I don't like it.

I'm all for signing up for a contract if it can turn a runtime error into a compile time error. However, this looks like it just makes more runtime errors. At that point, these seem no better than `assert` except for the fact that they promise to really assert (probably).

The article also points out a big problem which is "Importantly, this aspect of Contracts is why contract assertions must not be used for error handling and input validation: If a function has in-contract requirements to report certain events as errors, that handling must be done with standard C++ control statements that are not optional, never with contract assertions."

That sort of muddy definition of what contracts are supposed to be used for is almost certainly going to make a mess. It's not input validation, but parameter validation.. but not really validation but rather checks which error out, but it's not errors we are producing.

➕ show 12 replies
WalterBright • today at 7:04 PM

I used to be a big fan of contracts, and even implemented it in the Zortech C++ compiler back in the 90's:

https://www.digitalmars.com/ctg/contract.html

I implemented it in D as well. But, it just turned out to not be very useful.

ZuLuuuuuu • today at 2:05 PM

This reminds me the "Design by Contract" concept from Eiffel programming language:

https://en.wikipedia.org/wiki/Design_by_contract

https://www.eiffel.com/values/design-by-contract/introductio...

➕ show 2 replies
throwaway2037 • today at 8:45 PM

Unless you are doing trivial boolean comparisons, I always prefer a custom assert function that will also print a useful error message. Just telling me "Assertion failed: index < container.size()" isn't very helpful. What were the values compared?

Instead, my custom asset function (in C) looks like this:

    > void AssertWF(bool assertResult, char *format, ...)
Example:

    > AssertF(index < container.size(), "index:%d < container.size():%d", index, container.size());
If the first parameter is false, a detailed error message is printed:

    > fputs("Assert failed: ", stderr);
    > vfwprintf(stderr, format, ...);
    > abort();
gavinray • today at 2:53 PM

Random tidbit: I wrote a GCC compiler plugin years ago to add Contracts to C/C++ while waiting for this to make it into the standard

https://gavinray97.github.io/blog/adding-invariant-to-cpp-de...

The post turned out to be more useful for an intro to writing GCC plugins than anything, but at least I had fun

randyrand • today at 2:01 PM

Maybe just me, but huge complicated languages like C++ seem as unappealing as ever.

If I’m going to write code by hand, the requirement for a beautiful pleasant language is bigger than ever.

➕ show 4 replies
tsukikage • today at 2:56 PM

The article makes no mention of optimisation use cases. In case anyone already knows off the top of their heads and before I start digging for the answer, is part of the intent here for these to inform the optimiser stages, perhaps similarly to what the if (!(some_condition)) { __builtin_unreachable(); } idiom can achieve?

➕ show 2 replies
bluGill • today at 1:58 PM

I'm looking forward to seeing where these go in the future. Can solvers prove my code correct (at least in some trivial cases)? What should happen in a unit test (sometimes I want to test that my program handles out of range values, sometimes it is expensive top check and so I put the contract in to avoid the check at runtime...) Can/should the optimizer account for contracts (same question as unit tests).

➕ show 1 reply
MetaverseClub • today at 7:11 PM

I wonder what are the use cases in their mind when designing this. For runtime assertions and documentations, yeah, it would work but it works without contract arguably ok.

For formal verification, the design is way off.

nananana9 • today at 2:19 PM

Where do I put these?

If I put them in the header, I have to include half the world because I can't forward declare `Foo foo` argument if I want to check `foo.size() > 3` or similar in a pre/post-condition. This is a non-starter, keeping headers lean is the only way to not end up with 1 hour compiles.

If I put them in the cpp, they lose their only advantage over asserts - that they also double as documentation in the headers.

Did we add 50 pages to the standard for a slightly fancier assert? I feel like this could've been one builtin and a footnote:

contract_assert(expr) - if expr evaluates to false, the behavior of the program is undefined. Implementations are encouraged to emit a runtime check for this in debug builds, or a compiler error in cases where they can statically determine, that the assert will fail.

➕ show 3 replies
Surac • today at 7:51 PM

What are they even good forbid we can’t validate the input with? A convenient way to write down parameter ranges. Nothing more

➕ show 1 reply
preommr • today at 2:03 PM

I am very bullish on constraints based programming like this.

The main problem is code organization and syntax. Tacking stuff like this onto fuction declarations is too basic.

Ideally, I think we need better constructs, e.g. dettached constraints like to the function declaration. You can define constraints separately, in the same namespace or w/e, add notes, comments, etc. and the function declaration can be used with intellisense to jump to the constraint. You could even tag the defintions.

In modern AI-based workflows, the agent can pull up an explanation on the function, and point directly to the constraints, with strong confidence esp. if it's got explicit metadata.

➕ show 1 reply
literallyshared • today at 1:58 PM

I can see the appeal of having 'code as documentation' in header files, but personally I find any type of runtime asserts to be too heavy handed. Graceful error handling, in my opinion, is always preferable. This type of functionality is what is continuing to drive me away from C++. If your preconditions and postconditions matter, document them in a comment block.

➕ show 2 replies
creata • today at 6:37 PM

Are there any public examples of contracts in use, or of the Bloomberg library that contracts were based on?

xiaoyu2006 • today at 5:29 PM

I thought this is some Hoare-logic things ported to C++, but well it's only stanzarized guard statements.

account42 • today at 3:58 PM

Will compilers be able to optimize functions based the assumtions that contracts hold (even if they aren't being checked)?

abcd_f • today at 2:38 PM

As they used to say on slashdot:

From the "C++ design committee was so preoccupied with whether they could, they never stopped to think whether they should" department.

Asserts:

1. You don't like the being conditional on NDEBUG ot aborting the program - roll out your own. Will still be a one-liner.

2. You want them act as documentation of pre-conditions in headers - just add a comment there.

The only somewhat reasonable development here are the post conditions for functions with multiple returns, but post/s are dramatically less common than pre/s, so their utility is also debatable.

➕ show 2 replies
mal10c • today at 4:25 PM

I dislike this. But honestly, I dislike assert statements. I mainly write code that cannot fail. And if something does go wrong, I must handle that in an appropriate way. Asserts are never the way because they terminate the program.

In strictly my opinion, I don't have a problem with pre/post condition comments in a header. They clearly describe important details. Introducing yet another way to support asserts seems very unnecessary to me, but I guess I'm not obligated to use it either.

fithisux • today at 7:53 PM

C++ == --D

chelseahermes • today at 2:01 PM

[flagged]

ArgumentMoney81 • today at 4:41 PM

[flagged]

hsaliak • today at 2:13 PM

id' normally hate this but with agents this is awesome

➕ show 1 reply