It's somewhat funny to hear "minimum viable product" in the context of a language standard/specification. I'd never thought of adding a feature to a language in that way before.
The idea of design by contract (DbC) in C++ appears to have been around for a while too. The authors link to a "forthcoming companion paper" (currently a 404 error), but you can find proposals from as early as 2004 with the idea: https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n16...
(and potentially earlier, I just haven't seen one yet)
This is the MVP, as the subset of the all the various contract proposals that stands a chance to pass approval, as the feature has been extremely contentious with irreconcilable positions on some details.
I did my dissertation work on software contracts. They are generally useless: programmers won't write them, or will write them incorrectly. Moreover, the runtime enforcement dominates all but the most-expensive functions, and contracts become an antipattern for helper functions due to their enforcement cost.
Without intense compiler support and contract erasure such as David Van Horne's work, this is a dead idea that needs to stay that way.
I worked in the telecom business 15 years ago on 4G (LTE) and there it was considered a big savior compared to how it was done before.
Basically before they had a lot of error handling code and it was a significant part of the code base (don’t remember but let’s say 50%) and this error handling code had the worst quality because it is very hard to inject faults everywhere. So basically the error handling code had a lot of bugs in it which made the system fail to recover properly.
But DbC was a godsend in the way that now you didn’t try to handle errors inside the program any longer. Now the only thing that mattered was that a service should be able to handle clients and other services failing. And failure in a few well defined interfaces is much easier to handle. So the quality became much better.
What about the crashes then? Well, by actually crashing and getting really good failure point detection it was much easier to find bugs and remove them. So the failures grew less and less. Also, at that time I believe there were 70 ms between voice packages so as long as the service could recover within that timeframe, no cell phone users would suffer.
Plus of course much less error prone error handling code to write.
And as someone else said, DbC should never be turned of in production. Of course, in embedded systems, speed is not so important as long as it is fast enough to not miss any deadlines. And you need to code it so it doesn’t miss deadlines during integration and verification with DbC so there is no reason to turn them off in production.
Bertrand Meyer in his usual painstakingly detailed manner explains how to integrate DbC with Exception/Error handling in his paper Applying Design by Contract linked to here - https://news.ycombinator.com/item?id=42133876
It sounds like you're specifically talking about runtime-enforced contracts rather than ones that the compiler uses to prove compliance? Your first sentence makes it sound like you think all contracts are useless, but your last sentence makes it seem like you think they're useful if they're compile time.
I find it a very dubious assertion particularly with respect to performance. Well-written idiomatic code in most languages should validate inputs anyway; it's just done in an ad-hoc way - stuff like ArgumentException in .NET or ValueError etc in Python, for example. Contracts are just a way to formalize it, not only for the benefit of static analyzers, but also for better integration with existing tooling (generated docs etc).
And no, you don't have to write a code contract for every single function. Code contracts are most useful in the same exact place you'd do other kinds of contracts, like say documenting the public API of a library. From there it's diminishing gains to extend them deeper into the implementation, but in any case, one can always find a balance between performance and enforced contract checks. Not all code needs to be blazing fast, and erring on the side of correctness is preferable.
Yet companies like Eiffel Software, and Ada vendors with Ada/SPARK, are still in business with people paying for using their tools, in a day and age where many devs refuse to pay for their tooling.
I use them for all my code. They are far from useless. You never want to turn them off in production either since that's a source of important information. You are right programmers don't write them, but that says nothing about contracts and a lot about how programmers are trained.
Interesting. I am a fan of DbC (following Meyer's Applying "Design by Contract" - pdf at https://se.inf.ethz.ch/~meyer/publications/computer/contract...) though due to runtime costs (as you point out) i limit it to pre-conditions only everywhere (almost all "policy" part of the code and less on the "mechanism" side) and tighter pre/post-conditions on module boundaries only.
> programmers won't write them, or will write them incorrectly.
I think this is a matter of education and discipline and not an argument for not using DbC.
If it is okay with you could you share your dissertation and maybe highlight the key points which led you to your conclusion of "They are generally useless"? I think it would be useful to know.
Contracts are widely used in the form of asserts throughout many codebases and are generally seen as improving code quality and enabling more efficient designs.
Even something like accessing an element in an array is subject to the contract that the index is less than the size.
I have tried several times (a couple of decades ago) to introduce DBC in Python, using one of the many available libraries (for an overview: see https://lab.abilian.com/Tech/Python/DbC%20in%20Python/ ) but, like you, wasn't convinced.
I believe your argument on the performance penalty is right, and as a corollary, this implies that contracts are mostly useful if associated with a formal proof system. Contracts in production are probably a bad idea, in most cases.
> I believe your argument on the performance penalty is right, and as a corollary, this implies that contracts are mostly useful if associated with a formal proof system. Contracts in production are probably a bad idea, in most cases.
Agree! There is a sliding scale between testing contracts and proving them too. My labor of love for the past several years has been a tool for checking Python contracts using an SMT solver (using symbolic inputs over concrete paths): https://github.com/pschanely/CrossHair
That said, these days I think property-based testing gets you the ~same benefits as contracts, and is easier for most people to apply.
Wow, people miss the point of contracts. You never want to turn them off in production, because that's where all the weird shit happens that you never thought of. Contracts catch bugs in those times. Maybe people find them useless precisely because they turn them off.
Finally, somebody said it! I am always bemused when people say they turn off contracts in production code. They don't understand the difference between contracts (a program state guarantee) and testing for special/error cases (must be handled explicitly). The excuse usually given is runtime performance which can be mitigated by using a subset from pre/post-conditions/invariants.
But they also give you 4 different evaluation semantics (ignore, observe, enforce, quick_enforce) to tweak as needed. You don't need to do full checking everywhere and always.
That doesn't matter when it comes to concepts/ideas which are useful overall. In this context DbC is a general idea/technique (derived from the Floyd/Hoare/Dijkstra school of "Program Correctness") useful for "large scale" Software Engineering.
I'd assume the authors were aware of it, given that the original set of proposals from 2004-2006 directly compares facilities in D and Eiffel. Plus, you know, andrei.
Anyone interested in other languages that implement this should take a look at the SPARK subset of Ada. Pre and postconditions work in the same way and enforce the same behaviour described here (or at least that's what I understand it to do from a quick skim through)
For decades we have been using assert(input) and assert(output), so it's not exactly new. Forcing sanitary checks by the language runtime is an option, hence requiring contracts to spell out the range of valid input/output which is checked in debug mode. Otherwise, if it's optional, it will only be used by a subset of engineers. If its mandatory, it can cripple performance (unless we have unsafe scopes). Opt-out is always better than opt-in.
Assuming that this or something substantially identical does land for C++ 26 I think we should start betting on when SG23 (the committee's Study Group for "Safety and Security") is replaced by some hypothetical SG24 "Safety and Security No But Really".
We already know that because C++ Undefined Behaviour can cause what are called "Time Travel" defects and this paper doesn't do anything to prevent it, adding contracts in C++ can make your software less safe and induce more surprise behaviour. We also already know that C++ programmers tend to write erroneous UB tests when trying to grapple with edge cases that might induce Undefined Behaviour, setting off the very calamity they fear. So this new feature, rather than being (as its proponents claim) a way to improve the safety of C++ software, or neutrally becoming a dead letter as the UB "passes" contracts that in fact are not met, might instead become another footgun for the language.
A functioning SG23 should have caused this proposal to stall out until it can explain how it will prevent this problem, rather than merely re-stating the problem (in 3.6.4) and saying well that's unfortunate but maybe somebody else will fix it. That stance might be extremely unpopular with some C++ programmers, who believe they don't make mistakes, but as it stands this work will instead cause all the people who do make mistakes (which is in practice everybody) to regret using contracts. If SG23 isn't interested in preventing C++ from becoming even more unsafe, what's the point in the group existing?
Aha, this for some reason links an ancient version of the proposal and current versions do forbid time travel across the contract, so, the result is not strictly worse which is an important improvement, no sure whether SG23 was involved in that outcome but it's a good idea either way.
More recent revision: https://isocpp.org/files/papers/P2900R10.pdf. It seems like they've added a few things since this draft.
It's somewhat funny to hear "minimum viable product" in the context of a language standard/specification. I'd never thought of adding a feature to a language in that way before.
The idea of design by contract (DbC) in C++ appears to have been around for a while too. The authors link to a "forthcoming companion paper" (currently a 404 error), but you can find proposals from as early as 2004 with the idea: https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n16...
(and potentially earlier, I just haven't seen one yet)
Languages are software products as well.
Many features in Java, C#, C++ have evolved as MVP across several language revisions before.
Lambdas, type inference, modules, unsafe code, constexpr,...
This is the MVP, as the subset of the all the various contract proposals that stands a chance to pass approval, as the feature has been extremely contentious with irreconcilable positions on some details.
You have now :-)
I did my dissertation work on software contracts. They are generally useless: programmers won't write them, or will write them incorrectly. Moreover, the runtime enforcement dominates all but the most-expensive functions, and contracts become an antipattern for helper functions due to their enforcement cost.
Without intense compiler support and contract erasure such as David Van Horne's work, this is a dead idea that needs to stay that way.
I worked in the telecom business 15 years ago on 4G (LTE) and there it was considered a big savior compared to how it was done before.
Basically before they had a lot of error handling code and it was a significant part of the code base (don’t remember but let’s say 50%) and this error handling code had the worst quality because it is very hard to inject faults everywhere. So basically the error handling code had a lot of bugs in it which made the system fail to recover properly.
But DbC was a godsend in the way that now you didn’t try to handle errors inside the program any longer. Now the only thing that mattered was that a service should be able to handle clients and other services failing. And failure in a few well defined interfaces is much easier to handle. So the quality became much better.
What about the crashes then? Well, by actually crashing and getting really good failure point detection it was much easier to find bugs and remove them. So the failures grew less and less. Also, at that time I believe there were 70 ms between voice packages so as long as the service could recover within that timeframe, no cell phone users would suffer.
Plus of course much less error prone error handling code to write.
And as someone else said, DbC should never be turned of in production. Of course, in embedded systems, speed is not so important as long as it is fast enough to not miss any deadlines. And you need to code it so it doesn’t miss deadlines during integration and verification with DbC so there is no reason to turn them off in production.
Nice.
Bertrand Meyer in his usual painstakingly detailed manner explains how to integrate DbC with Exception/Error handling in his paper Applying Design by Contract linked to here - https://news.ycombinator.com/item?id=42133876
It sounds like you're specifically talking about runtime-enforced contracts rather than ones that the compiler uses to prove compliance? Your first sentence makes it sound like you think all contracts are useless, but your last sentence makes it seem like you think they're useful if they're compile time.
Which they are (compile time) with Ada / SPARK, without any runtime costs.
I find it a very dubious assertion particularly with respect to performance. Well-written idiomatic code in most languages should validate inputs anyway; it's just done in an ad-hoc way - stuff like ArgumentException in .NET or ValueError etc in Python, for example. Contracts are just a way to formalize it, not only for the benefit of static analyzers, but also for better integration with existing tooling (generated docs etc).
And no, you don't have to write a code contract for every single function. Code contracts are most useful in the same exact place you'd do other kinds of contracts, like say documenting the public API of a library. From there it's diminishing gains to extend them deeper into the implementation, but in any case, one can always find a balance between performance and enforced contract checks. Not all code needs to be blazing fast, and erring on the side of correctness is preferable.
Yet companies like Eiffel Software, and Ada vendors with Ada/SPARK, are still in business with people paying for using their tools, in a day and age where many devs refuse to pay for their tooling.
Would be interesting if they pay because they want those tools or if they pay because they fear rewriting some old tools using those languages.
I use them for all my code. They are far from useless. You never want to turn them off in production either since that's a source of important information. You are right programmers don't write them, but that says nothing about contracts and a lot about how programmers are trained.
Interesting. I am a fan of DbC (following Meyer's Applying "Design by Contract" - pdf at https://se.inf.ethz.ch/~meyer/publications/computer/contract...) though due to runtime costs (as you point out) i limit it to pre-conditions only everywhere (almost all "policy" part of the code and less on the "mechanism" side) and tighter pre/post-conditions on module boundaries only.
> programmers won't write them, or will write them incorrectly.
I think this is a matter of education and discipline and not an argument for not using DbC.
If it is okay with you could you share your dissertation and maybe highlight the key points which led you to your conclusion of "They are generally useless"? I think it would be useful to know.
Contracts are widely used in the form of asserts throughout many codebases and are generally seen as improving code quality and enabling more efficient designs.
Even something like accessing an element in an array is subject to the contract that the index is less than the size.
A reference for your dissertation?
The usefulness (or lack thereof) of contracts was famously discussed in 1997 in this paper: https://www.irisa.fr/pampa/EPEE/Ariane5.html (with additional comments here: https://www.irisa.fr/pampa/EPEE/Ariane5-comments.html ).
I have tried several times (a couple of decades ago) to introduce DBC in Python, using one of the many available libraries (for an overview: see https://lab.abilian.com/Tech/Python/DbC%20in%20Python/ ) but, like you, wasn't convinced.
I believe your argument on the performance penalty is right, and as a corollary, this implies that contracts are mostly useful if associated with a formal proof system. Contracts in production are probably a bad idea, in most cases.
> I believe your argument on the performance penalty is right, and as a corollary, this implies that contracts are mostly useful if associated with a formal proof system. Contracts in production are probably a bad idea, in most cases.
Agree! There is a sliding scale between testing contracts and proving them too. My labor of love for the past several years has been a tool for checking Python contracts using an SMT solver (using symbolic inputs over concrete paths): https://github.com/pschanely/CrossHair
That said, these days I think property-based testing gets you the ~same benefits as contracts, and is easier for most people to apply.
Wow, people miss the point of contracts. You never want to turn them off in production, because that's where all the weird shit happens that you never thought of. Contracts catch bugs in those times. Maybe people find them useless precisely because they turn them off.
Finally, somebody said it! I am always bemused when people say they turn off contracts in production code. They don't understand the difference between contracts (a program state guarantee) and testing for special/error cases (must be handled explicitly). The excuse usually given is runtime performance which can be mitigated by using a subset from pre/post-conditions/invariants.
C++ contracts as currently designed can execute 4+ times per call to do full checking. That gets expensive quickly.
But they also give you 4 different evaluation semantics (ignore, observe, enforce, quick_enforce) to tweak as needed. You don't need to do full checking everywhere and always.
Is anyone using Eiffel language in the real world? The community seems so tiny, barely existing.
That doesn't matter when it comes to concepts/ideas which are useful overall. In this context DbC is a general idea/technique (derived from the Floyd/Hoare/Dijkstra school of "Program Correctness") useful for "large scale" Software Engineering.
Definitly, otherwise Eiffel Software would have closed shop by now.
SAL is wildly successful in the Windows world and is basically a contract language embedded in C macros.
Contract programming for C++ was implemented back in the 90's.
https://www.digitalmars.com/ctg/contract.html
It also appears in the D programming language:
https://dlang.org/spec/contracts.html
The programming world has massive anterograde amnesia.
"Contract programming for C++ was implemented back in the 90's."
-> Did the proposal authors contact you or refer to your work (or any other previous work)? It not, that would be a shame.
"It also appears in the D programming language"
-> Do people use it?
> Did the proposal authors contact you
No
> or refer to your work (or any other previous work)?
No
I presume they simply didn't know about it. I emailed the authors.
> Do people use it?
Yes
I'd assume the authors were aware of it, given that the original set of proposals from 2004-2006 directly compares facilities in D and Eiffel. Plus, you know, andrei.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n19...
I had missed this, the paper does mention D:
"Programming languages such as Eiffel and D have a Contracts facility; this paper proposes a Contracts facility for C++."
> Yes
The tiny subset of D userbase, which is tiny in its own.
Anyone interested in other languages that implement this should take a look at the SPARK subset of Ada. Pre and postconditions work in the same way and enforce the same behaviour described here (or at least that's what I understand it to do from a quick skim through)
Wasn't Eiffel the first "design by contract" language? https://en.wikipedia.org/wiki/Eiffel_(programming_language)
Yes, with key books based on it.
The authors are aware of SPARK and are trying to bring that to C++.
For decades we have been using assert(input) and assert(output), so it's not exactly new. Forcing sanitary checks by the language runtime is an option, hence requiring contracts to spell out the range of valid input/output which is checked in debug mode. Otherwise, if it's optional, it will only be used by a subset of engineers. If its mandatory, it can cripple performance (unless we have unsafe scopes). Opt-out is always better than opt-in.
Assuming that this or something substantially identical does land for C++ 26 I think we should start betting on when SG23 (the committee's Study Group for "Safety and Security") is replaced by some hypothetical SG24 "Safety and Security No But Really".
We already know that because C++ Undefined Behaviour can cause what are called "Time Travel" defects and this paper doesn't do anything to prevent it, adding contracts in C++ can make your software less safe and induce more surprise behaviour. We also already know that C++ programmers tend to write erroneous UB tests when trying to grapple with edge cases that might induce Undefined Behaviour, setting off the very calamity they fear. So this new feature, rather than being (as its proponents claim) a way to improve the safety of C++ software, or neutrally becoming a dead letter as the UB "passes" contracts that in fact are not met, might instead become another footgun for the language.
A functioning SG23 should have caused this proposal to stall out until it can explain how it will prevent this problem, rather than merely re-stating the problem (in 3.6.4) and saying well that's unfortunate but maybe somebody else will fix it. That stance might be extremely unpopular with some C++ programmers, who believe they don't make mistakes, but as it stands this work will instead cause all the people who do make mistakes (which is in practice everybody) to regret using contracts. If SG23 isn't interested in preventing C++ from becoming even more unsafe, what's the point in the group existing?
SG23 is already the Safety and Security No But Really group. Multiple safety proposals were already ignored for C++26
Prohibiting time traveling UB in all cases is proposed by P3352 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p33...).
Aha, this for some reason links an ancient version of the proposal and current versions do forbid time travel across the contract, so, the result is not strictly worse which is an important improvement, no sure whether SG23 was involved in that outcome but it's a good idea either way.
SG23 has done a lot in C++26 around this.
Are there HTML version of these docs? Would make it easier to read without having to download a PDF.
The pdf rendered nicely for me.