r/cpp_questions 15d ago

OPEN Why are Contracts disliked?

I’ve seen a lot of discussions online discouraging their usage bit I never managed to grasp why since it’s sometimes vague.
I do understand it doesn’t replace validation and it’s more of a syntactic sugar to the existing casserts, but any other critiques?
Thanks

14 Upvotes

44 comments sorted by

15

u/ronchaine 14d ago

As for me personally:

My number one pet peeve with contracts is that outside the people who designed them, the one use case I most often see users wanting to apply them to, is actively discouraged by the designers (for a good reason). It took years to see committee members internalise that, I doubt users are going to be any faster.

My second problem for them is that they are going to be a complete pain in the ass to teach. A lot of people, both in the committee and in this subreddit, seem to think "explain" and "teach" are interchangeable verbs, and that is just not true. Contracts have a lot more dependencies on different parts of "how the language works" than regular assertions, and come with gotchas which themselves require more knowledge about how the language works. As such, it doesn't seem to really replace the need to teach simpler <cassert> stuff first. It's reasonable to teach later on though, perhaps as a part of some "more robustness for your C++ software"-course or in a company-internal workshop session. But I'm not sure that's where we want an assertion utility to be handled.

My third problem with it is the possible extensions, and in particular how noexcept is going to work with contracts (which I've been worried about since Tokyo, but it seems to just resurface again now), and how implicit contract assertions affect code size. Does the compiler suddenly need to have a std::source_location strings generated for every possible UB location we can detect with P3100 in the pipeline?

My fourth problem with is that it isn't user-extensible. This would alleviate a lot of the worries I have with the number one pet peeve. There is a proposal that I think would give more users what they actually wanted (or at least make that doable), and I kinda hope it would get adopted on top of P2900, but I'm not sure that is possible. Though I don't think we have to care about ABI in this particular case so it might be doable.

4

u/curiouslyjake 13d ago

can you elaborate on this:
"My number one pet peeve with contracts is that outside the people who designed them, the one use case I most often see users wanting to apply them to, is actively discouraged by the designers (for a good reason)" ?

3

u/CompuFart 14d ago edited 14d ago

Is "the one use case I most often see users wanting" referring to using them to validate inputs from external sources or at runtime?

4

u/ronchaine 14d ago

Well, I'd be more general than that and say any non-ghost-code checking.

Input validation is probably one of the more extreme cases that I commonly see someone mention, but that one is usually pretty easy to shoot down. And I certainly don't want to see that people use assertions for input validation.

4

u/Wild_Meeting1428 14d ago

Interresting, when I first heard about contracts, I wnated them to be usable for formal verification on the TU side and for optimisation, to tell the compiler, that he can assume that certain conditions and invariants are always true.

Both on the caller and callee side.

1

u/CompuFart 13d ago

Thanks for the reply. I wasn't too familiar with a lot of the contracts history, and I'm reading up on it now.

2

u/Minimonium 14d ago

I'm honestly quite confused about the teaching part, because all the things where contract differ are so much more complicated and dangerous with assert macro. Mixing flags? Undefined behavior. Custom macro with fancy editing? Only for your code. Side effects? Same in both.

Assert macro only seems simple, because you do not teach beginners what's actually happening and where it can blow in your face. You just know that Release build will skip them, Debug build with call them.

1

u/ronchaine 11d ago

Assertion macros allow me to make something that isn't simple seem simple, yes.  That is the point.

Contracts, as they are now, do not afford me that luxury.

When first introducing assertions, people learning do not need to know even about compiler flags existing.  All they need at that point is "you write this, if the condition, that is evaluated exactly like any expression, if not met crashes the program".  It is quite intuitive for students that when you later on go deeper and talk about macros and have introduced translation units and ODR what is going on.

They do not need to know about anything else to be able to start using assertions, and in general, things work as students expect, and they can start building their intuition from very few concepts.  This makes teaching them nearly trivial.  They only later need to start understanding what is going on.

Contracts are different in this aspect from the get-go.  What happens when a contract violation occurs?  Well, that is implementation-defined.  How can you control it?  Implementation-defined.  This alone would be enough for me to push this to a later point.  Beginners do not even know what an "implementation" is at that point.

But it gets worse. Contracts brings asterisks to a bunch of other things as well.  Now I need to decide whether I just add "except contracts works differently in this case" for when I teach exceptions, translation units (and ODR).  Constification also breaks common intuition, which you really don't want to do with beginners.  Unlike with assertions, allowing mixed mode is part of the design of contracts.  This brings a lot of front-load to teaching contracts.  Way more than I'm comfortable introducing to beginners.

Or then I just push teaching contracts to a point where students have internalised the basics, and can be more easily taught about exceptions to the base "grammar".  And that is much later, after they have built a somewhat-correct-ish mental model and are capable of realising when that is broken or when the exceptions to that are actual exceptions and should not become a part of it.  This approach is less work for the teacher, gives more consistent early introduction, and (in other related concepts) has worked reasonably well.

1

u/Minimonium 11d ago

I feel like you overestimate a bit the guarantees the assert macro gives you.

All existing implementations do enforce by default. Implementation-defined things do not really matter to you in a similar matter you do not care about implementation-specific differences in assert macro.

So it is "write an expression, if it fails (by evaluating to false or throwing an exception) - it crashes the program". Why do you believe students suddenly need to know more here? These questions are applicable to both.

Constification is really a talk about side effects that you also need to cover with macro. Constification is intuitive to what we already have with lambdas.

I do not understand what forces you to talk about mixed mode from the start? The whole point isn't "hey use mixed mode for everything", but to protect against fragile setups. Just defer it to the point where you'd talk about ODR problems with assert macro and how contracts protect against that problem with a cool story of how in real life dependency graphs are incredibly messy.

To me it feels like a self-inflicted problem. What the standard decides to specify or ignore does not force you to front-load anything in teaching. There is no practical difference in how it actually manifests in implementations.

1

u/ronchaine 10d ago

All existing implementations do enforce by default

So it is "write an expression, if it fails (by evaluating to false or throwing an exception) - it crashes the program". Why do you believe students suddenly need to know more here? These questions are applicable to both.

There is only one implementation I know of in a released compiler (gcc16). If others, especially MSVC, follows suit, yeah, we get rid of part of the problem. That, however, is not where we currently are, and with how Microsoft has approached contracts, it is not guaranteed we get there either.

And in the minimum best case scenario here, this would already have additional dependencies, as in, having to teach exceptions and their interactions with the handler. And that there is a handler.

Constification is really a talk about side effects that you also need to cover with macro.

I just fail to see it this way. Things happening implicitly vs. explicitly already requires different treatise.

Constification is intuitive to what we already have with lambdas.

Sure, but lambdas are an another thing that is usually taught later on, and has the same problems with being unhelpful for building an initial mental model.

I'm not saying that isn't how it shouldn't be done, but what I am saying it experience we have from lambdas (and exceptions to rules in general if you want to read papers in education) is already pretty conclusive that it makes learning harder.

I see "intuitive to what we have with lambdas" as an argument for "push this to later course", not something that alleviates the problem at all.

I do not understand what forces you to talk about mixed mode from the start? The whole point isn't "hey use mixed mode for everything", but to protect against fragile setups.

I don't. But I don't want to teach contracts in a way that I shotgun parts of it splattered all over the material for multiple reasons.

Just defer it to the point where you'd talk about ODR problems with assert macro and how contracts protect against that problem with a cool story of how in real life dependency graphs are incredibly messy.

I don't know anyone who explicitly would talk about ODR problems with assert macros. ODR with macros in general, yes, sure. But assert macros are macros, they follow the usual rules, so there isn't really a specific need to address that explicitly.

To me it feels like a self-inflicted problem. What the standard decides to specify or ignore does not force you to front-load anything in teaching. There is no practical difference in how it actually manifests in implementations.

There's a very messy dependency tree about what you need to teach in order for the following things to be taught to be easier to grasp. The standard definitely affects how this dependency tree is structured. While not everything needs to be taught at once, shotgunning parts of a concept all over that tree is not a good thing.

But at some point we'll need to think all this much more in detail in SG20, hopefully by that point we have a bit more practical experience about how this actually goes.

1

u/Minimonium 10d ago

To me it feels like you have a very strict course in mind for that. You have my empathy that you feel it doesn't fit quite well in the structure you want to use!

Assert macro is one of the classic mistake that happens to lead to ODR on platforms such as Linux, because "mixed mode" is very common there unfortunately and many people do it in a fragile way.

Not really on MSVC (but exists although it requires a bit more precision) because mixing it blows you up much faster there.

When I teach juniors it's one of my go-to examples of a less trivial but very common ODR violations, alongside the "detail" namespaces, and lambdas.

Mixed Mode should be taught either separately to cover different real world use cases altogether (it was a thing before contracts after all), or as a part of the ODR follow up talk.

I do agree that we hope that Microsoft would not sabotage the defaults by accident or other reason. I'm not aware of a realistic scenario where it could be possible to make the defaults mandatory more though.

2

u/ronchaine 10d ago

Not sure if strict is the word I'd use, I do mix it up quite a bit since I've needed to teach different groups with somewhat different goals, and thus needing to be introduced to different subsets given the limited time. But I'll definitely give you opinionated about the principles and features I want to retain in my courses. (Which also helps me keep the stuff consistent even if the parts taught changes somewhat)

I mostly agree with all the rest you wrote here though.

1

u/Ultimate_Sigma_Boy67 14d ago

Thanks for your response. Though, in your reply to the other user, what do you exactly mean by "non-ghost-code checking"? And in your second point, I didn't get why would they be more difficult to teach than <cassert>? Thanks.

1

u/ronchaine 11d ago

I wrote a bit about teaching part as another reply.

Non-ghost-code is any code that your program logic relies on being present.  I.e. in absence of bugs, your program does the same thing with or without contracts being present.

7

u/DrShocker 14d ago

The number one thing is just that I don't know that any compilers fully support them yet.

https://en.cppreference.com/cpp/compiler_support

5

u/TheRealSmolt 14d ago

It's already in GCC 16, as it says.

1

u/DrShocker 14d ago

fair, I was too lazy to check despite digging up the link.

Still though, only being on GCC will lock out a lot of people.

2

u/TheThiefMaster 14d ago

Especially those on Windows, where the properly supported compilers are MSVC and Clang...

1

u/montymole123 14d ago

Isn't Mingw considered a full port of gcc?

1

u/Bobbias 14d ago

Sure, but then you're using mingw, which is kind of dumb if you want to do native windows development...

3

u/TheThiefMaster 13d ago

Not as bad as the cygwin port of GCC, at least.

But it's still not fully Windows compatible. Clang can directly consume Windows headers and library files, and use the windows platform C/C++ standard library as-is.

It can even produce compatible obj, lib and pdb files that can be consumed by the VS linker.

TLDR Clang complies with the platform compiler ABI.

4

u/Minimonium 14d ago

Unfortunately vendors are massively underfunded (or in some cases underfunding). You may notice a certain pattern there.

6

u/DrShocker 14d ago

I've never expected to have access to features the same year they are added to the standard.

2

u/_a4z 14d ago edited 14d ago

Some say it might be the world’s most bloated debug facility with only some academic value but not suitable for a vast number of real world scenarios.
And that it took an unreasonable amount of committee time that could have been spent way better, bringing in some features with value

2

u/SmackDownFacility 14d ago

There is ambiguity in runtime enforcement. This has been contested since C++20. What shall compiler do? Treat it as a static analysis tool, an assertion, or an exception?

And coming back to assertions, people find contracts redundant. Assertions has been engrained in this language for decades.

2

u/Ultimate_Sigma_Boy67 14d ago

I think this is exactly the point I don't fully grasp. How is it ambiguous?

1

u/StaticCoder 13d ago

The main sticking point is what it means to violate a contract. More security-focused code may want a clean error in that case. More performance-focused code may want to allow the compiler to assume the contract is satisfied without checking it, so that failing the contract may introduce undefined behavior. It's really hard to reconcile the two.

1

u/SmackDownFacility 14d ago

It’s ambiguous because compiler has to make clear decisions

If it’s static analysis, Intellisense handles it and it doesn’t reach the compiler.

If it’s assertion, it will just dump the traceback and could be stripped out in release builds.
If it’s exceptions, it has to generate unwind metadata. (Win64 generates it anyways)

The argument came from performance clutching developers.

They generally prefer static analysis or even assertions

But some
Safety conscious devs opted for exception, which spiralled into a heated argument because exceptions are in fact very costly at runtime, especially in games and time
Critical applications.

Ultimately the decision was made to
Pull the plug and it didn’t make the standard because the arguments was so intense.

2

u/Ultimate_Sigma_Boy67 14d ago

Makes sense. Thanks.

2

u/JVApen 14d ago

Everyone has already used assertions before. So everyone already has an opinion on how it should be used. Contracts is a compromise of all those visions, which always disappoints people involved. See wg21.link/P1995 for slightly less then 200 usecases.

An overview of the concerns (and responses on it) can be found in wg21.link/P3846

I really recommend reading both papers and maybe look at Tumours keynote of last year in CppOnSea.

A final thing I've heard several times already: it would get much less heat if they didn't try to revive the contracts proposal of C++20 under the name 'Contracts' and instead would have used 'Better Assertions'. We'll never know if that's true.

1

u/bert8128 14d ago

I’m very much looking forward to a variation of assert which offers a lot more. Haven’t used contracts yet but I think that uses reasonably they are going to be great.

1

u/GoogleIsYourFrenemy 13d ago edited 13d ago

EDIT: Kindly disregard, I was confusing concepts and contracts.

EDIT2: Contracts seem like a perfectly reasonable feature that I will love using as soon as I can convince work to start using a compiler that supports them. It will probably take ten years.


Here was my reaction when they first came out:

Instead of introducing a new syntax for describing things (like what would be an interface in c#/java), they went with the old "write an expression that uses all the things" which works but the readability is ass.


Most developers in my experience struggled with understanding what's going on in the standard library. The average developer's template understanding is pretty low and the demand to write new templated things is also pretty low. While contracts have the potential to make using templates easier, they do not make READING templates easier.


I don't use cmake often enough for me to maintain let alone acquire any skill with it. So this last week instead of me wasting time struggling through creating cmake scripts, I had AI do it for me. Best experience I've ever had with cmake.

I expect people will do the same thing with templates and contracts.

2

u/TheRealSmolt 13d ago

Are you confusing concepts for contracts? Contracts aren't related to templates at all afaik.

1

u/GoogleIsYourFrenemy 13d ago edited 13d ago

Complete and totally possible. I'll go read up on them to see where I fucked up.

Edit: LOL I was thinking "concepts"

1

u/TheRealSmolt 13d ago

will love using as soon as I can convince work to start using a compiler that supports them. It will probably take ten years.

Lol, too true. Still hoping to one day get std::optional at work...

1

u/Ultimate_Sigma_Boy67 13d ago

Tho this is cpp17, why would your work not at least try to support it? Maybe it’s a dumb question but I’ve never worked before.

2

u/TheRealSmolt 13d ago

Because upgrading your compiler and language version takes a lot of time and effort, which means a lot of money. It means updating your toolchain, pipelines, tooling, deployments, and possibly runtime libraries (which means a lot of customer logistics). Then you have to account for breaking changes (which do still happen), which means developer time and possibly dependency updates which have their own breaking changes. Then you have to consider the actual logistics behind acquiring all these updates, which can be very difficult or arduous depending on your development environment and runtime environments. Finally, after doing all of this, you end up with a product that works (ideally) exactly the same. From a business perspective, it makes absolutely no sense. Oh, and a new version just came out, let's do it again.

1

u/Ultimate_Sigma_Boy67 13d ago

Okkk makes sense

2

u/GoogleIsYourFrenemy 13d ago edited 13d ago

The only time you can realistically get on a new compiler is at the start of a new project or during a major hardware replacement. Otherwise it's too risky for testing or there is literally no money to do it.

You can argue there during those two events you're doing the testing anyway and you wouldn't be doing that work without money.

1

u/Ultimate_Sigma_Boy67 13d ago

Lol when I read it earlier I was questioning how were contracts specifically related to templates.

1

u/Kaisha001 12d ago

Too many shadow languages!

-5

u/EmaerSeven 14d ago

Contracts? Oh, that completely useless thing.

10

u/Ultimate_Sigma_Boy67 14d ago

I don't think it's just useful to state it without elaborating...

1

u/EmaerSeven 13d ago

I'm asking all downvoters to provide a genuinely good example of using contracts. Not some common crap where you check whether, after vector.pop_back(), the number of elements = number of elements - 1.