Document no: P2032R0
Date: 2020-03-02
Authors: Joshua Berne
Reply-to: jberne4@bloomberg.net
Audience: SG21

Contracts — What Came Before

Introduction

Prior to the formation of SG21 there were a number of different potential solutions proposed for contract based programming in the language. With the formation of SG21, a large number of use cases that any future contract solution might need to satisfy have been presented and polled on (see P1995 for the use cases and the initial poll results).

In order to better understand these use cases, a number of people expressed questions about how those use cases might be met with standard C++20 with no language based contracts, and how each of the prior language proposals might satisfy these use cases. We hope this exposition helps in understanding the use cases better, and helps to leverage the work that has gone before into determining our future direction for language based contracts.

Revision History

Differences from first draft:

Methodology

There are 4 primary language variations that we wish to evaluate for their merits at satisfying the SG21 use cases:

Rather than enumerate all possible variations that could be chosen, we will focus on comparing P1429 with no literal semantics and P1607 with no contract levels.

For each of these variations, we will assign a value in the range 0-100 for each use case with roughly the following meanings:

The goal of these numbers is to give a rough feeling for worth. In the future, we expect to see use cases given some weight (based partly on importance to the community and partly on distinctness from other use cases), and then combined with these numbers to give each solution a total value that can be used to understand how effecitvely is satisfies the needs of the community.

Note that the long term goal here is not to give a number to say "you must vote for this since it has a higher number" but rather to provide a value that can be used to see "this solution measurably improves support for use cases that I personally might not consider important but that others do see as a priority".

Additionally, a number of features could conceivably be built in a compatible way on top of any of these proposals using a system built with preprocessor macros (and such macros are the only viable way to build a system with no language support). Because of this, some scores are split into two numbers, the first being a judgement on how well the proposal satisfies the use case "out of the box", the second being how the proposal can be used with a macro facility above it to meet the specified use case.

Use Cases

# CodeAs AIn Order ToI Want To N4842
C++20
N4820
Pre-Cologne Draft
P1429
Semantic Level Control
P1607
Literal Semantics
1 dev.reason.knowl Developer Reason explicitly Annotate my program anywhere in the code with my current understanding of its structure or execution 25 90 90 90

Without a specific contract checking facility there are still ways to annotate a program with information about program contracts, but those are limited to either comments (with no validation or normative effect), the classic C assert macro, or larger nonstandard macro-based facilities (with no consistency in representation across different implementations). Typical usage would be within a function writing something like this:

void sqrt(double n) {
  assert(n >= 0.0);
  BSLS_ASSERT(n >= 0.0);
}

All of the contract proposals that were considered introduced the same syntax for expressing an expectation that a certain boolean predicate was true at specified points in a program. These satisfy most common use cases in the wild for contract predicates, although being only boolean predicates makes them fall short of being able to capture many more involved or not runtime checkable aspects of a function contract. These include the ability to express this within a function body as assertions like this:

double  sqrt(double n) {
  [[ assert : n >= 0.0 ]]
  // ..
}

More notably, annotations of expectations about execution could be added on function declarations as well -- something not possible with a solely language based solution -- like this:

void sqrt(double n) [[ pre : n >= 0.0 ]];
2 dev.reason.confidence Developer Reason explicitly Express a spectrum of confidence in my annotations, from "unsure" and asking for validation, to "sure" and asking for some effect to be applied (eg. "maybe", "definitely", "assume" 'something') 40 0 0 0 /40
3 dev.reason.importance Developer Reason explicitly Express a spectrum of importance of my annotations, from "critical" (eg. bring the system down) to "minor" (eg. lead to a slower fallback) 40 0 0 0 /40

While BDE's bsls_assert does not provide confidence as something that can be used to control contract behavior, it is not hard to envision that such a thing could be built into a macro-based solution.

Build-level-only solutions do not capture this at all (where N4820 and P1429 presented default, audit, and axiom as the only extra annotations that could be put on a contract, and those were intended to capture cost of checking not confidence).

P1607's literal semantics do not provide this directly, but here again one could envision combining a macro-based solution to choose literal semantics that would capture confidence or importance and compute behavior based on that.

4 dev.reason.cost Developer Reason explicitly Express a spectrum of expected cost at compile or runtime of my annotations, from "unrunnable" to "expensive" to "cheap" 40 80 80 0 /50

A macro-based solution would again be able to be built to use an expression of the cost of checking to determine how a contract will be treated, and BDE does exactly this with the following variations on how a contract can be checked:

void foo(int x) {
  BSLS_ASSERT_OPT(x != 0);
  BSLS_ASSERT(x < Utils::getMaxXValue());
  BSLS_ASSERT_SAFE(factorial(x) < Utils::getMaxXFactorial());
}

The default, audit, and axiom levels captured this similarly:

void foo(int x) {
  [[ assert default : x != 0 ]];
  [[ assert audit : x < Utils::getMaxValue() ]];
  [[ assert axiom : is_reachable( staticranges[x].begin(),
                                  staticranges[x].end() ) ]];
}

Similar to the case for confidence and importance, any system that was built on top of literal semantics for P1607 with macros would be able to choose to capture cost as part of that control of contract behavior.

5 dev.reason.behavior Developer Reason about executions Have annotations affect the execution of my program in accordance with my expectations 25 75 90 90

N4820 contracts allowed for contract checks to either introduce undefined behavior or be checked at runtime.

P1429 and P1607 provide more flexibility by exposing the choice of 4 different semantics for contracts, with the primary difference being the granularity of that control.

6 dev.reason.sideeffects Developer Reason about executions Ensure annotations do not substantially change the meaning of my program whether enabled or disabled 100 0 50 50

The primary meaning of this use case is that there should be a way to use the contract facility (on or off) without undefined behavior. This does not preclude the ability to introduce undefined behavior - but it needs to be optional. N4820 fails to provide this. A macro-based facility, barring bugs, should be able to easily provide this. P1429 and P1607 provide the ignore semantic with no violation-introduced undefiend behavior.

Both P1429 and P1607 did not fix the fact that any side effects in a predicate are treated as undefined behavior. Note that P1670R0 was scheduled for Cologne which had one proposal for an attempt to address that.

7 dev.reason.behaviorcontrol Developer Reason about executions Have the effect of annotations on execution be user controllable (based on whatever aspects, if any, are available). 65 50 55 25 /70

A macro-based solution can be built to use command line and in-code annotations to determine contract behavior. P1607 and a macro-only facility would both be able to provide any form of behavior control that users might wish to build, with more consistency to the behaviors that different options might give with P1607.

N4820 and P1429 contract control is much more limited, primarily being only doable at the build level of granularity.

8 dev.adapt Developer Adapt and progress with my project Be able to easily change my confidence, importance, or other properties of my annotations over time 40 25 50 25 /75

The build-level supporting options (N4820 and P1429) allow changing the one attribute they expose (cost). The macro-based solutions would have to build support for this, but can clearly put that in the sou rce code and thus make editing the attributes of an annotation easy to edit.

An important thing to note is that safely changing annotation properties in released software is equivalent to introducing that contract freshly in any deployments that ignored the old 'level' and check the new 'level'. The ability to introduce the check at the new 'level' with a continuing semantic is essential to safely adding any checks to already deployed software. N4820 and P1429 both only allow the control of continuation at a very high level, thus forcing a user to turn continuation on for all existing checks in order to safely add checks that continue. P1607 provides the granularity to change this decision on a per-contract basis.

9 dev.readable.syntax Developer Have readable annotations Have annotations with a succinct and elegant syntax 40 80 80 70
10 dev.parsable Developer Interoperate with tools or persons A syntax that can both be parsed and can be reasoned about semantically 40 75 75 70
11 cppdev.syntax.familiar C++ Developer Get up to speed Have annotations use familiar syntax 50 75 75 75
12 cppdev.syntax.cpp C++ Developer Get up to speed Have annotations use C++ syntax 50 75 75 75
13 cppdev.syntax.reuse C++ Developer Reuse code Have annotations use my custom types or functions 75 75 75 75
14 cppdev.location C++ Developer Have a single source of truth Use same source file for both code and annotations 100 100 100 100

Obviously N4820 provides no explicit syntax and is limited to macros, but that still allows for using readable C++ in the annotations.

P1607 likely requires macros to facilitate any global controls over behavior, so is a slightly worse syntactic option than what N4820 and P1429 provide (which have identical syntax).

15 dev.readable.keywords Developer Have readable annotations Have annotation keywords or names with intuitive, clear, and unambiguous meanings 10 50 50 60

Given that it provides no new keywords for contracts, readability is going to be entirely dependent on what macro based facility is being used with N4842.

For N4820 and P1429, the clarity of 'default' is fairly opaque, and a huge amount of reflector discussion and contention has revolved around the meaning and use of axiom, so they fair poorly here.

P1607 removes the contentious keywords, but introduces new bespoke keywords that while clear are not necessarily intuitive to all, along with needing to build any other controls on top of those with macros, so it seems only slightly better in this regard.

16 dev.readable.priority Developer Have readable annotations Have my contract specification to be visually primary, and secondary information (syntax, hints, roles, levels, etc.) to not be distracting 15 10 10 10

All of the attribute-based solutions put the meta-information first before the expression, counter to what this use case is asking for. A macro-based solution could choose to prioritize information differently, but would also be restricted in how the information gets passed into the macro.

17 dev.tooling Developer Interoperate with tools or persons Expose annotations to tools that might leverage them (eg. code linter, static analyzer, semantic prover, compiler sanitizer, binary analyzer, code reviewer, etc.) 0 75 75 75

Entirely macro-based facilities would need to be ubiquitous enough for tooling vendors to choose to support them explicitly, along with those tooling vendors needing to work around the difficulties of managing pre-preprocessor based analysis.

18 cppdev.syntax.macros C++ Developer Support modern features Minimize use of macros 0 50 60 50 /0

Obviously not very much can be done with the base language without macros.

P1607 would require macros to support any form of global controls, so it gets the lowest rating for this use case, while P4820 would be usable for basic applications without macros, and P1429 would be slightly more flexible without needing to resort to macros.

19 cppdev.modules C++ Developer Support modern features Be interoperable with modules 10 25 25 25

A purely macro based solution would have the worst interaction with modules.

The language-based solutions were expected to have basic support for modules, since all would have landed in C++20, but no specific modules-related features were initially planned.

20 cppdev.coroutines C++ Developer Support modern features Be interoperable with coroutines 25 25 25 25
21 api.coroutines C++ API Developer Use coroutines Define and check pre and post conditions as I would a regular function 0 0 0 0
22 api.coroutines.invariants C++ API Developer Use coroutines Define and check invariants over all entry and exit points from a coroutine (to its awaiter or promise) 0 0 0 0

All of the solutions would work perfectly fine within the body of a coroutine. Coroutine handling of contracts on inputs, outputs, and states when resuming a coroutine had not had any discussions or support planned in the proposals as they existed, so none of the proposals support coroutines any better than a purely macro-based solution.

23 cppdev.concepts C++ Developer Support modern features Be interoperable with concepts 25 25 25 25

Nothing about the prior facilities seems to benefit or hinder the use of concepts.

24 cppdev.existing.std C++ Developer Use the standard library in-contract Codify existing exposition-only standard library requirements 50 50 50 50

Many of the preconditions and postconditions of the standard library can be expressed as boolean expressions, and so are encodable using the facilities that were provided.

25 cppdev.debugger C++ Developer Use Debugger Have runtime able to launch a debugger from an annotation if necessary 25 40 40 40

As much as any C++ program is able to do something like signal that a debugger should be opened, a macro based solution could invoke the platform-specific functions that would enable that (such as __debugbreak() or raise(SIGTRAP)). All of the prior solutions also provided a consistent place to put such a function call by allowing for setting a custom violation handler, and due to that being globally consistent we rate them slightly higher.

This is still not a standardized facility, so no solution completely satisfies this use case within the standard itself.

26 cppdev.build.legacy C++ Developer Use existing build modes Have annotations affect executions depending on my existing build modes (eg. Debug or Release modes in VS) 25 0 0 0 /10

Those solutions that would use macros to do global control (N4842 and P1607) would be able to reference _NDEBUG or similar macros usually associated with "debug" and "release" builds as input to how they configure contracts. The standard, and the build levels specified in N4820 and P1429, are however completely disconnected from one another.

27 cdev.contracts C Developer Write contracts on my functions Specify contracts in a way standardizable as part of the C language 10 0 0 0
28 cdev.identifiers C Developer Write contracts on my functions Use contracts with macro-safe keywords that are reserved C names (i.e., _Pre, _Post, _Assert, etc.) 10 0 0 0

None of the contract specifications as a language feature would have been palatable to the C standards committee, since they all require being able to attach meaning to an attribute, as well as make use of new identifiers with special meaning (which are unfriendly to standardize in the macro-heavy C world.)

A pure C++ macro based contract solution would, however, possibly be implementable in a fashion that is equally usable from C code.

29 cdev.violationhandler C Developer Write contracts on my functions Have a common violation handler for both violated C and C++ contracts 50 25 25 25

With no C interoperability easily possible, and the violation handler specified in terms of an opaque class type (std::contract_violation), implementing that violation handler i C would not have been feasible.

It is, however, likely that any C-based contract solution would be able to bridge to and from the C++ contract violation handler, since there is no particularly complex functionality in the violation handler or the violation object itself.

30 cdev.ignorable C Developer Write contracts on my functions Make all contract semantics optional (so as not to change WG14-N2385 6.7.11 p2) 50 25 25 0

P1607's explicit semantics require that they behave in a specific way when asked for. Similarly, there is an expectation with N4820 and P1429 that build levels can be set to something other than off, but they do allow global control to do that (so at least one potential program behavior would be buildable without needing to make contract annotations do anything).

Obviously a macro-based solution would be able to provide this kind of feature.

31 ccppdev.interop Mixed C/C++ Developer Maintain mixed code base Not lose contracts when crossing languages 0 0 0 0
32 cdev.cppinterop Mixed C/C++ Developer Write contracts on my functions Expose my contracts to C++ developers through 'extern "C"' declarations of my functions 0 0 0 0

A pure macro-based facility exposes no contracts to callers, regardless of what language the callers are calling from. The language-based facilities would not have readily supported standardizing by WG14.

33 api.communicate.inputsoutputs API Developer Communicate my interface to users Document the expected inputs and expected outputs on my interface 25 75 75 75
34 api.establish.check API Developer Establish a contract Have validation inform me which output values are unexpected or invalid 25 75 75 75
35 api.establish.values API Developer Establish a contract Have validation inform user which input values are unexpected or invalid 25 75 75 75
36 api.establish.preconditions API Developer Establish a contract Have contracts specify their pre-conditions as logical predicates 25 75 75 75
37 api.establish.postconditions API Developer Establish a contract Have contracts specify their post-conditions as logical predicates 25 75 75 75

Precondition and postcondition checks within a function do something to document inputs and outputs, as do comments that are readily available without a language feature.

The language proposals all included the common feature of [[pre]] and [[post]] to express this information directly on function declarations, and have those get checked at runtime.

38 api.establish.validate_invariants API Developer Establish a contract Have validation inform me which class invariants are violated 5 5 5 5
39 api.establish.invariants API Developer Establish a contract Have contracts specify their class invariants as logical predicates 5 5 5 5
40 cppapi.invariants C++ API Developer Write classes Declare class invariants that all of my public functions need to maintain 0 0 0 0

Neither a macro based facility or the language proposals allowed for specifying at a class level invariants that would be automatically checked (barring manually adding class invariants as pre and post conditions on every single function.)

41 api.express.values API Developer Express predicates Make reference to either the values of my inputs, or other in-scope identifiers 75 75 75 75
42 api.establish.changedvalues API Developer Establish a contract Make reference to the before and after values of in-out variables (ie. passed by pointer or reference) in post-conditions 40 0 0 0
43 api.establish.changedmembers API Developer Establish a contract Make reference to the before and after values of mutable class members (eg. new_size = old_size+1 after push_back) in post-conditions 40 0 0 0
44 api.establish.changedstate API Developer Establish a contract Make reference to the before and after values of global state (eg., global >= old(global) + 1) in post-conditions 40 0 0 0

A macro based facility can similarly expose macros to control the enablement of arbitrary code at arbitrary scopes, and so enables storing values between calling time and return time manually.

The language-based facilities allow for referencing inputs and outputs, with the caveat that inputs were only referencable in outputs if they were not changed. The language-based facilities explicitly prevented any form of making additional code execute if contracts were enabled, and thus removed the ability to store data between the start and end of a function call.

45 api.extend.exceptionsafety API Developer Extend contractual aspects Annotate operations as being exception safe 0 0 0 0
46 api.extend.threadsafety API Developer Extend contractual aspects Annotate operations as being thread safe 0 0 0 0
47 api.extend.atomicity API Developer Extend contractual aspects Annotate operations as being atomic (ie. all or no changes become visible) 0 0 0 0
48 api.extend.realtime API Developer Extend contractual aspects Annotate operations as real-time (ie. guaranteed to complete within a time frame) 0 0 0 0
49 api.extend.determinism API Developer Extend contractual aspects Annotate operations as being deterministic (ie. same outputs for same inputs) 0 0 0 0
50 api.extend.purity API Developer Extend contractual aspects Annotate operations as functionally pure (ie. no side effects) 0 0 0 0
51 api.extend.sideeffects API Developer Extend contractual aspects Annotate operations as having global side effects (ie. write to singleton, file, network, or database) 0 0 0 0
52 api.extend.complexity API Developer Extend contractual aspects Annotate algorithmic complexity 0 0 0 0

No codification of these features is baked into the language itself or added by the previous proposals.

53 api.express.runnability API Developer Express unrunnable contracts Be able to use a predicate that is not evaluated at runtime, because it might be unsafe to run or have stateful side effects 0 0 75 75
54 api.express.undefined API Developer Express unrunnable contracts Be able to use a predicate that doesn't have a definition, because it hasn't been written yet, or is infeasible to run 0 0 75 75
55 api.express.uncheckable API Developer Express uncheckable contracts Be able to use a predicate that is not evaluated, because it is simply a semantic placeholder for a tool 0 0 75 75
56 api.express.unimplementable API Developer Express uncheckable contracts Be able to use a predicate that cannot have a complete definition, because it is inexpressible in the language 0 0 75 75

There is no current in-language way to express predicates that will not be executed at runtime.

N4820 had unchecked contracts leave their evaluation as unspecified, thus making any predicate that has UB or has side effects potentially evaluated (specifically, the wording said "it is unspecified if the predicate of an unchecked contract is evaluated".)

P1429 and P1607's assume semantic, however, attempted to capture the original intent of the contract proposals and make unchecked contracts not be evaluated, thus enabling the use of predicates that are not themselves safe to ever evaluate.

57 api.establish.responsibility API Developer Establish responsibility boundaries Inform users which errors are the responsibility of the caller, and which are the callee 0 50 50 50
58 api.resp.preassert API Developer Establish responsibility boundaries Annotate assertions inside function bodies that indirectly test preconditions (such as malformed data discovered while performing the algorithm) should be reported to the caller as precondition failures 0 0 0 0

Macros within a function are unable to readily gather information about what called the function, thus making it infeasible to identify calling code in a precondition violation in a wholely macro-based facility.

N4820 made it possible to change that for [[pre]] annotations on a function declaration, allowing for the reported source line to be the calling location if the implementation is willing and able to do so. There was, however, still no facility to explicitly point at a caller being the source of a problem when the problem gets detected within the body of a function (or, for instance, when delegating to another function without duplicating that function's preconditions explicitly).

59 api.contract.interface API Developer Have contract as part of my interface Declare contract when I declare the function 0 100 100 100

This is not doable with macros, but was inherent in the proposed contract solutions.

60 api.contract.private API Developer Keep my user interfaces clean and narrow Be able to access private implementation details of the class so I don't have to widen public interface to declare predicates 100 100 100 100

A macro within a function has full access to private data members of that function's class, as do contracts in all of the language contract proposals.

61 api.contract.redeclaration API Developer Keep my public interfaces clean and concise Place function contract conditions on any declaration (e.g., on redeclarations at the bottom of the header, or on the definition in an implementation file, where they are less distracting). 0 0 0 0

A macro-based facility obviously has no contracts on any declarations. The language based proposals did not allow for contracts on any declaration except the first one.

Note that P1320R1 was going to be presented in cologne and sought to alter this state.

62 api.contract.errorhandling API Developer Move contract violation out of error handling Replace uses of error handling to express contract violation (eg. operator[](size_t n) noexcept [[pre: n < size()]] instead of throwing) 50 50 50 50

This is a design decision when defining an API that could be readily accomplished with any contract facility.

63 cppapi.class.preconditions C++ API Developer Maintain a class hierarchy Ensure overriding methods have same or wider preconditions (see: Liskov substitution principle) 0 40 40 40
64 cppapi.class.postconditions C++ API Developer Maintain a class hierarchy Ensure overriding functions meet their base class postconditions when their base class preconditions are met (see: Liskov substitution principle) 0 40 40 40
65 cppapi.class.variability C++ API Developer Maintain a class hierarchy. Allow overriding functions to have narrower preconditions/wider postconditions if I want to 0 0 0 0

A wholely macro based facility has no way to automatically integrate with function overrides.

The language proposals all required that virtual functions have exactly the same preconditions and postconditions, and so allowed for a subset of what would be Liskov substitutable.

66 api.class.publicinterface C++ API Developer Express public class invariants Express a restriction on the public interface of a type that all callers of the type can depend upon: can mention only public members, and is checked on entry and exit from this type's code 0 0 0 0
67 api.class.publicinvariants C++ API Developer Express public class invariants Check invariants before and after every public method (when called from outside the type, not when one member function calls another) 0 0 0 0
68 api.class.publiccalls C++ API Developer Express public class invariants Check invariants before and after calling functions that are not part of this type (including virtual calls) 0 0 0 0
69 api.class.baseinterface C++ API Developer Express base class invariants Express a restriction on the protected interface of a type that derived types can depend upon: can mention only protected and public members, and is checked on entry and exit from this type's code 0 0 0 0
70 api.class.baseinvariants C++ API Developer Express base class invariants Check invariants on entry and exit of every protected method (when called from the derived type, not when one base member function calls another) 0 0 0 0
71 api.class.basecalls C++ API Developer Express base class invariants Check invariants before and after every call to a virtual function (when calling to the derived type) 0 0 0 0
72 api.class.privateinterface C++ API Developer Express private class invariants Express an internal restriction on the private implementation of a type, can mention any member, and is checked on entry and exit from this type's code 0 0 0 0
73 api.class.privateinvariants C++ API Developer Express private class invariants Check invariants on entry and exit of every public method (when called from outside the type, not when one member function calls another) 0 0 0 0
74 api.class.privatecalls C++ API Developer Express private class invariants Check invariants before and after calling functions that are not part of this type (including virtual calls) 0 0 0 0

A macro-based facility is not part of the declared interface to any class, but only part of the implementation.

The language proposals were limited to functions but not types, and always had private access.

75 api.class.testing C++ API Developer Test my classes For every member or friend function in my class, run my unit test framework with checking enabled for every assertion at the point where it is written, and check every postcondition at every non-exceptional exit, and test my class invariants on entry and exit from this type's code 0 0 0 0

This level of control is not providable for macros or the language proposals.

76 cppapi.contracts.async C++ API Developer Enforce contracts in async code Express contracts on callbacks such as std::function, function pointers, or references to functions, lambdas, or function objects 0 0 0 0

This would require contracts be part of a function type. Macros are not even part of a function declaration, let alone its type, and the previous language proposals did not choose to make contracts part of a function type either.

77 cppapi.contracts.exception C++ API Developer Enforce contracts in exception safe code Express contracts on exceptional exit 0 0 0 0
78 cppapi.variadic C++ API Developer Use contracts with variadic templates Allow predicate (fold) expansion 0 0 0 0

Neither of these are viable on the.

79 int.conform.violation Integration Developer Conform to a contract Be informed any time an interface's contract is violated 25 50 50 50
80 int.conform.postconditions Integration Developer Conform to a contract Verify results from a call are expected output values 25 50 50 50

This is the purpose of a checked contract facility, though the granularity of control to limit to or at least include a particular (or all) interface is not there for all proposals.

81 int.build.headeronly Integration Developer Build multiple libraries Use contract-enabled header-only libraries 50 100 100 100
82 cpplib.headeronly C++ Library Developer Use templates Be able to ship header only library 50 100 100 100

A macro based facility is likely to depend on having a supporting library exist to make customization and violation handling available.

Nothing about the proposed solutions required this (or, as a language facility, a library got the supporting functionality needed for free from the compiler's runtime environment).

83 int.build.binaries Integration Developer Build multiple libraries Use contract-enabled binary libraries 100 100 100 100
84 int.build.binarycounts Integration Developer Build multiple libraries Only be required to manage a small, common set of build/link configurations 75 40 25 75

Policies on how many different builds are managed and deployed are entirely up to users when the facility's controls are all done through macros (either entirely in N4842 or on top of literal semantics in P1607).

N4820 includes 5 distinct build configurations that might be desired by clients of a library, and P1429 increases that number to 32, though most are only interesting in special cases and it is likely that individual vendors would find a small set that are of actual interest to their clients.

85 int.build.control Integration Developer Debug multiple libraries Enable checks only within a selected library 50 35 35 50
86 int.build.control2 Integration Developer Debug multiple libraries Enable checks on multiple libraries simultaneously 50 35 35 50

The build levels are global, with conditional (and potentially no) support for using mixed build levels across different libraries. Macro based solutions are viable as long as any individual contract always has the same meaning in different translation units (without ODR violations).

87 int.debug.callsites Integration Developer Debug multiple call sites Enable checks only on selected call sites 0 25 25 0

None of the solutions allowed for a function to be called with different checking levels without violating the ODR.

88 int.violations.information Integration Developer Correct failed checks Be informed what check failed, when, where, and how 75 100 100 100
89 int.violations.transmit Integration Developer Correct failed checks Transmit check failure information in environment-specific ways (logs, email, special hardware traps, popup windows, blazing sirens, etc). 50 90 90 90
90 int.violations.custom Integration Developer Correct failed checks Install custom violation handler where I can inject custom logic to trap errors 50 90 90 90
91 int.violations.common Integration Developer Unify violation handling Be able to override how library violations are handled in the combined software to point into my handling code 50 90 90 90

All of the facilities support checking contracts at runtime and being informed of details of the violation. The language proposals included a pluggable violation handler, although compiler vendors were allowed to not make that customizable.

A pure macro-based facility suffers from needing to do this for all of the contract facilities that might be defined and used within a given fully assembled program.

92 int.violations.override Integration Developer Be independent of build environment Be able to define and override violation handler via source code 15 0 0 0

This might be doable with a fair bit of complexity in a macro-based facility, and there was no support for this in the language proposals.

93 int.build.minimize Integration Developer Minimize checking overhead Disable library postconditions, asserts, and invariants, without disabling library preconditions (assuming the library is tested and stable and my code is not) 25 0 0 25
94 int.control.build Integrated Software Provider Ensure the combined software is correct At build time, turn on and off what checking happens. 25 0 0 25
95 int.control.runtime Integrated Software Provider At runtime, control what checking happens. Turn checks on at run time 25 0 0 0
96 int.conrol.subsets.build Integrated Software Provider Ensure the combined software is correct Turn on any subset of individual (call site) checks on at build time 25 0 0 25
97 int.control.subsets.runtime Integrated Software Provider Ensure the combined software is correct Turn on any subset of individual (call site) checks on at run time 25 0 0 25
98 int.control.subsets Integrated Software Provider Ensure individual features are correct Have a way to audit (named or semantic) subsets of checks for various deployments 25 0 0 25
99 int.testing.control Integrated Software Provider Define "Code Under Test" Selectively enable checking for a set of functions which could name either an individual function or an overload set 15 0 0 15
100 int.testing.controltypes Integrated Software Provider Define "Code Under Test" Selectively enable checking for a set of types and all their members 15 0 0 15
101 int.testing.transitivity Integrated Software Provider Define "Code Under Test" Selectively enable checking for a set of types and all their transitively nested types and members 5 0 0 5
102 int.testing.modules Integrated Software Provider Define "Code Under Test" Selectively enable checking for a translation unit or module and all (non transitive) types and functions within 5 0 0 5

Different forms of build and runtime control could be built into the macro-based facilities with varying levels of difficulty. N4820 and P1429 provided only a global level of control, limiting greatly the ability to control contract enablement at finer granularities. Implementing some of these forms of granularity in the preprocessor might, however, be very complicated.

103 int.consistency Integrated Software Provider Ensure the combined software is correct Verify all annotations are globally consistent when integrated 0 0 0 0

There is no support for this form of checking on a macro-based facility, or from the language proposals.

104 int.build.common Integrated Software Provider Manage binary delivery Be able to use the same executable regardless of contract enforcement mode 15 0 0 0

A C++20 based facility could determine checking based on runtime configuration instead of only compile-time configuration. The language proposals did not allow for that.

105 int.build.unchecked Integrated Software Provider Test final deliverable Turn off build time checking to remove checking overhead 40 50 50 40
106 int.runtime.unchecked Integrated Software Provider Test final deliverable Turn off run time checking to remove checking overhead 50 50 50 50

Macros and the language proposals had minimal concepts of "build time checking", but they do all enable a global ability to turn off such checking. That same global ability can be used to turn off runtime checking.

107 int.build.optimize Integrated Software Provider Test final deliverable Turn on run time optimization to leverage annotation assumptions 25 50 75 75
108 pdev.speed Performance Sensitive Developer Enable better performance Annotate my code with assumptions, likelihoods, or reachability information that a tool might not be able to deduce, but that I would be confident of 25 50 75 75
109 pdev.morespeed Performance Sensitive Developer Enable better performance Be able to give statically-unprovable facts to current and novel optimizers in terms of semantics my program does not depend-on but optimizers can't figure out 25 50 75 75
110 pdev.footgun Performance Sensitive Developer Enable better performance Accept responsibility for a malformed program that might result from eventually false information given by my annotations 25 50 75 75

A macro based facility would be able to enable optimizations, but that is likely going to have limited direct support from most compilers. (Generally, this would leverage either __unreachable() or __assume().)

N4820 made optimizations enabled for ALL unchecked contracts, while P1429 and P1607 gave mechanisms to opt into that in varying ways.

111 cpplib.insulation C++ Library Developer Control the tradeoff between need for client recompilation and contract condition visibility Insulate contract conditions with the function definition, or insulate only the definition while putting contract conditions on a redeclaration - visible to static analysis tools in all TUs. 25 50 50 50

Macro based contract checks will always be in the function body and thus fully insulated from clients.

The contract annotations of the language proposals could be equivalently put in function bodies with [[assert]] or on the declarations, thus giving some control over insulation. The ability to have them visible to clients through a redeclaration but not visible on the initial declaration was not, however, in the initial proposals (but was proposed but not seen by EWG in P1320R1.)

112 lib.maintenance.noconfig Library Provider Simplify maintenance Not require extra build steps to be documented 25 25 25 25
113 lib.integration.noconfig Library Provider Support successful integration Not require extra build steps to be learned or performed 25 25 25 25

Any contract facility that allows control without source code manipulation will require some build time control, either through compiler flags or macros, though all should have been usable with some default behavior if no explicit choices were made at build time.

114 lib.maintenance.nowhining Library Provider Simplify maintenance Not have users complain about my product due to modifications of annotations resulting from their build configuration 75 0 0 75
115 lib.integration.nowhining Library Provider Support successful integration Not have my users accidentally modify my careful annotations 75 0 0 75

A macro based facility could provide concrete semantics similar to P1607, thus making contracts that cannot have their behavior changed from the command line.

N4820 and P1429 contracts are always subject to build modes, leaving no way to enforce that a particular behavior is applied to a given contract annotation.

116 arch.nomacros Technical Architect Maintain quality of code base Express assertions in a way that does not rely on C macros (i.e., there is no valid technical reason for a programmer not to use the new way, including space, time, tooling, and usability/complexity reasons, compared to C's assert macro) 0 50 50 50

Contract checks without a language facility are not feasibly doable without macros.

All of the language proposals require macros in some form or other to satisfy many of the use cases in this document, but still provide a basic contract checking facility with no macros used at all.

117 arch.complete Technical Architect Have a consistent and holistic contracts facility Specify preconditions/postconditions/assertions/invariants that express my expectations about the expected valid state of my program in the form of compilable boolean expressions, that can be checked statically or dynamically (as opposed to disjointed state where these features are factored into bits) 0 75 75 75

Obviously the language does not have this now, and the language proposals all attempted to provide this.

118 hardware.performance Hardware Architect Improve system-level performance Be able to design new hardware + optimizations, carefully dovetailed into one another, that depend on statically-unprovable facts being annotated in the code 0 25 75 75

N4820's inability to have contracts that are never executed prevents this from being leveraged for many novel features. P1429 and P1607's assume semantic fixed this.

119 sdev.bestpractices Senior Developer Set an example Demonstrate best practice in defensive programming 50 25 50 50

Any basic contract checking facility can be used to implement defensive programming.

N4820's implicit assumption of any unchecked contract, however, is unlikely to ever be viewable as a best practice to use by anyone.

120 sdev.quality Senior Developer Enforce code quality Discourage reliance on observable out-of-contract behavior by causing check failure to hard stop program or build 50 50 50 50

This behavior is available in any of the facilities, though not as strongly enforced when a user has control over the violation handler.

121 sdev.maturity Senior Developer Enforce mature, finalized contracts Disable continuation on violation of stable and correct individual contracts 50 25 25 75
122 sdev.control Senior Developer Enforce mature, finalized contracts Disable remapping of semantics on stable and correct individual contracts 50 25 25 75

The global controls of N4820 and P1429 do not allow for control over an individual contract's behavior (continuing or not, checked or not) based on the maturity of that specific contract.

123 jdev.understand.contracts Junior Developer Understand the API A uniform, fluent description of expected input values, expected output values, side effects, and all logical pre and post conditions 0 75 75 75
124 jdev.understand.violations Junior Developer Understand the API Be informed when my usage is out of contract 50 75 75 75
125 jdev.understand.buildfailures Junior Developer Understand the program Know why my software is not building 50 75 75 75
126 jdev.understand.aborting Junior Developer Understand the program Know why my software is aborting 50 75 75 75
127 jdev.understand.omniscience Junior Developer Understand the program Know why my software is out of contract 50 75 75 75
128 jdev.understand.buildviolation Junior Developer Understand the program Know that my program or build was halted due to contract violation 50 75 75 75
129 jdev.bestpractices Junior Developer Improve my code Learn about software best practices by example 50 75 75 75

Without a language feature contract descriptions are library-specific and not uniform. With it, the only non-uniformity comes in when libraries build extra infrastructure on top of the language-provided facility.

A library and a language-based facility will, however, be able to provide a user understandable details of why a contract violation might have made a program abort or fail to compile.

130 jdev.understand.all Junior Developer Understand the facility Be able to build a program with contracts after reasonably short tutorial 50 75 75 75

Whether with a library or any of the proposed language features, simple contract use remains simple.

131 jdev.understand.keywords Junior Developer Understand the facility Have keywords with precise and unambiguous meanings 0 25 25 75

Without a language feature there are no new keywords. N4820 and P1429 include axiom which has shown to have significant disagreement over what meaning it has in the context of contracts (see P1672).

The keywords provided by P1607 are all very precisely defined.

132 adev.fast Agile Developer Iterate quickly Be able to write and modify contracts quickly without heavy boiler plate or up front cost 0 75 75 75

The general use of contracts once they are a language feature is quick to get started on. Without a language feature, getting started requires acquiring or implementing a library to provide the feature.

133 adev.evolve Agile Developer Safeguard evolving code Assert against conditions I am aware of but not finished handling fully 20 0 0 75

Without a language-based facility the only way to enter a not-yet-implemented contract is as a comment, which is of limited utility.

P1607's ignore and assume semantics both allow for referencing undefined functions, and thus enable writing a planned contract while preserving writing the implementation of that check for a future sprint. N4820 provides no way to get that semantic for a contract annotation, and while P1429's assume semantic would, there is no way in code to write such a contract.

134 bdev.confidentiality Business Developer Maintain confidentiality Not expose diagnostic information (source location, expressions, etc.) in the software I deliver to clients, even when I choose to have contracts enforced in the software I deliver 25 0 0 0

A macro-based library could choose to forgo including this information, or provide flags to control that.

None of the language features proposed include that ability.

135 pdev.safety.isolation Performance Sensitive Developer Have safety critical paths Isolate safety checks from performance annotations 25 0 0 0

A macro-based library could provide this distinction. None of the language proposals include this, and importantly all of them allow for a contract to be assumed and thus subvert any future "safety checks" that attempt to handle out-of-contract behavior more elegantly.

136 pdev.safety.critical Performance Sensitive Developer Have safety critical paths Retain checking even when optimizing with performance annotations 25 0 15 20

N4820 provides no way to turn checking off locally without bringing in assumption. P1429 at least provides a way to build an application without assumption of checks, and macro-based solutions on top of P1607 or a fully-macro based solution would be able to allow for this kind of distinction with some effort.

137 qdev.checkall Quality Sensitive Developer Enable full checking Ensure all checks (pre, post, assert, invariant) are enabled 25 100 100 75
138 qdev.fuzz.testing Quality Sensitive Developer Catch unexpected failure modes Log all predicate failure during fuzz testing 25 100 100 75

A disparate set of macro-based libraries makes it hard to turn on all checking.

N4820 and P1429 allow for this to be done very easily with build modes. P1607 allows for code to subvert this kind of control by providing explicit semantics for a particular contract that cannot be externally altered.

139 qdev.correctness Quality Sensitive Developer Validate correctness Signify the predicates that should be verified by an analysis tool 25 50 50 25
140 qdev.tooling Quality Sensitive Developer Manage multiple tools Signify subset of individual annotations to be consumed by a specific kind of verification tool 25 50 50 25
141 qdev.tooling.control Quality Sensitive Developer Manage multiple tools Signify subset of individual annotations to be consumed by a specific instance of verification tool 25 0 0 25

It can be argued that the primary intention of axiom was to only provide information to static analysis tools, so both of the proposals that include that have that here, even though the wording itself added in undefined behavior to that level, and made no mention of this purpose.

A macro-based facility could integrate with a static analysis tool for this purpose, but would require tools to choose to support it.

142 qdev.tooling.undefined Quality Sensitive Developer Manage multiple tools Use predicates that may not be understood by all instances of verification 0 0 25 25
143 qdev.tooling.undefinedkinds Quality Sensitive Developer Manage multiple tools Use predicates that may not be understood by all kinds of verification 0 0 25 25

Only P1429 and P1607 allow predicates to remain undefined if not referenced and not checked at runtime.

144 qdev.tooling.behavior Quality Sensitive Developer Manage multiple tools Integrate the results of that static checker into how my program behaves in different ways: assume proven predicates, make unprovable predicates ill- formed, etc. 25 0 0 25

P1607 or a wholely macro-based facility provide the only direct way to integrate the results of analysis into specific behaviors for contract checks.

145 qdev.testing Quality Sensitive Developer Unit test predicates Override failure handler to trigger test failure instead of termination 25 50 50 50

All of the proposals included a conditionally supported custom violation handler which could be used to test that checks are actually checked at runtime in a unit test (at least, for noexcept functions). A macro-based facility can accomplish this as well (and this is the foundation of all negative testing in BDE, see bsls_asserttest.h for an example of how that might be implemented).

Importantly, the lack of by-default runtime changing of violation handler behavior means that a custom violation handler must be written to get the full functionality needed - when testing that a check is violated, you want the violation handler to throw so you can recover to do more tests, while when testing anything else you want a hard error because a bug has been found by your testing.

146 qdev.handler.testing Quality Sensitive Developer Unit test violation handlers Have a way to run handler on all combinations of available build modes 25 0 0 0

The proposal in N4820 and all of its descendants prohibited any way to directly invoke the violation handler. A macro-based facility can expose this with relative ease (and, for example, BDE does with the macro BSLS_ASSERT_INVOKE).

147 crit.control Critical Software Developer Have a verifiable release system Be able to control the configuration of contracts from a central point 25 75 75 50

A macro based facility, or macros built on top of P1607, could provide this - with the major limitation that there might be multiple such facilities to configure within a single application.

N4820 and P1429 only provide global controls over how contracts behave.

148 crit.noundef Critical Software Developer Avoid undefined behavior Have contract violation at run-time always have well-defined behavior 25 0 75 50

Only P1429 allows removing any use of an assume-like semantic from contracts. A macro-based facility can choose to provide that (using various forms of non-portable or semi-portable implementations). N4820 provides no way to turn off contract checks without them introducing undefined behavior.

P1607 Allows for this, but also allows for the explicit use of the assume semantic when desired, which does not allow for altering how it behaves.

149 crit.recovery Critical Software Developer Not have a faulty program lead to catastrophic failure Have access to a recovery path after contract violation 25 0 75 50
150 crit.redundancy Critical Software Developer Not have a faulty program lead to catastrophic failure Be able to express error handling that may be redundant with contract checking 25 0 75 50
151 crit.interaction Critical Software Developer Not have a faulty program lead to catastrophic failure Not have contract build or run modes possibly be able to change or disable related error handling in any way 25 0 75 50
152 crit.testing Critical Software Developer Meet code coverage requirements Be able to run both success and failure branches in my test environment 25 0 75 50

With the right build or diligently avoiding the use of the assume semantic recovery paths work properly after violations, although the check itself would need to be duplicated.

153 crit.locality Critical Software Developer Be assured a critical violation uses a critical recovery path Couple recovery path to a specific contract within the source 25 10 10 10

The only viable option with the language proposals would be a custom violation handler that access a diligently updated thread-local recovery path when there is a violation. There is no innate support for this built into the facilities.

154 crit.production.checking Critical Software Developer Have redundant layering Be able to continue to run checks in a production environment (even after formal testing is complete) 25 50 75 75

P1429 gives complete flexibility about what levels are checked or not in the builds you choose to deploy to production. P1607 and a macro-based facility allow building that same kind of functionality.

155 crit.more.coverage Critical Software Developer Maximize coverage Be able to run checks in a production environment that are considered "cheap" compared to the expected cost of entering an invalid state 25 75 75 50

N4820 and P1429 both explicitly consider cost as the primary metadata that can be put on a contract annotation (via a level of default or audit). This doesn't allow for any more granularity in that expression of cost, but it is

156 crit.noassume Critical Software Developer Avoid unexpected or undefined behavior Ensure checks will never be __assume'd/__builtin_assume'd by the compiler as if they were facts injected into the program (otherwise, if such an assumption ever failed, I would be running a different program that is not equivalent to the one I wrote; assumptions can expand the set of possible executions by injecting facts not otherwise knowable to the compiler) 0 0 50 0

Only P1429 provides the a way to configure contract annotations to never be assumed.

157 sec.noattacks Security Sensitive Developer Limit attack vectors Be unable to insert code paths (eg. violation handlers) at run time (eg. build time only) 0 90 90 90

None of the contract facilities allow any runtime alteration of the violation handler.

Note importantly that an application may choose to install a custom violation handler that delegates to something that is runtime controllable, so this restriction is circumventable if the compiler allows for setting a custom violation handler.

158 sec.certify Security Sensitive Developer Deliver a certified product Have build tool only link to a preapproved violation handler 0 90 90 90

The wording for N4820 and its derivatives allows for a compiler to choose to not allow for changing the violation handler to something user defined.

159 analysis.runtime User of Analysis Tools Improve runtime correctness Have runtime checks generated by the tool 0 0 0 50
160 analysis.optimization User of Analysis Tools Improve runtime performance Have runtime optimizations generated by the tool 0 0 0 50

None of the proposals or the language itself support direct integration with a static analysis tool. Explicit literal semantics, however, could be injected into code by such a tool to generate computed contract behavior - runtime checking, optimizations, or otherwise.

161 analysis.symbolic User of Analysis Tools Allow symbolic analysis Have symbolic proofs for soundness and consistency performed before compile time 25 50 75 75
162 analysis.compiletime User of Analysis Tools Allow code analysis Have code source, AST, or instruction inspection during compile time 25 50 75 75

Proofs of soundness are certainly aided by stating contract annotations and asking for validation of those annotations. Tooling will need to catch up to leverage this and do such proving.

Many such proofs rely on being able to state additional facts that are not easy to codify as boolean checks, and those are often needed to thoroughly prove even much simpler predicates, so none of the proposed solutions are complete for this purpose.

163 analysis.binaries User of Analysis Tools Allow binary analysis Have binary inspection after compile time 0 50 50 50

In principle contract checks could be carried forwarded and recorded in binaries to allow for post-compile verification. It seems unlikely that a non-builtin facility would be standardized in binary files in such a way.

164 analysis.information User of Analysis Tools Improve the quality of analysis Be able to hint to the analyzer information it may be unable to deduce from source code alone (eg. 5 / opaque(); [[ opaque() != 0]]) 0 0 0 75

None of the proposals allow for hints that are exclusively for the static analyzer to use, but the P1607 ignore semantic could be used for such a purpose.

165 analysis.legacy Provider of Analysis Tools Extend my existing engine Be able to map pre-existing contract features in tools to a standardized language syntax 0 25 25 75
166 large.modernize Large Codebase Owner Modernize my code base Introduce standardized contracts to replace my macro-based contracts 0 25 25 75

Only a very limited legacy framework (such as the C assert macro) that completely falls within the functionality provided by N4820 would be migratable without drastic changes in behavior.

P1607 sought to provide more flexibility for reimplementing most legacy frameworks in terms of common semantics provided by the language.

167 teach.bestpractices Teacher Demonstrate best practice Be able to express defensive programming, programming by contract, and test driven development to introductory students 25 100 100 100
168 teach.standardized Teacher Demonstrate best practice Not rely on custom libraries or proprietary extensions 0 100 100 100 /50
169 teach.lifecycle Teacher Demonstrate best practice Demonstrate mock lifecycle by switching simple compiler flags to control which checks are enabled 0 50 50 25 /75
170 teach.portable Teacher Manage many students Have examples compilable by a standard compiler on any system 0 50 50 50 /40

Basic defensive programming is directly expressable through any of the proposed contract facilities. Without a language feature, custom libraries must be used and that is not portable.

Advanced features of contract lifecycle are more difficult to teach when not directly supported, and none of the proposals provide a complete solution for that behavior (see P1332 for a broad discussion of what sorts of lifecycle considerations impact contract use), while only P1607 provides a way to do so at all at a non-global granularity.

171 teach.dumbstudents Teacher Manage many students Have examples that are easy to build without digression into build systems 0 50 40 30

More advanced usages with P1429 or P1607 are clearly dependent on more complicated configuration. N4820 provides a simple set of flags (build modes) that would arguably be easiest to teach and use.

Note that nothing in P1429 prevented the support for the same set of build modes in addition to the more specific semantic per level setting that it required.

172 teach.teachable Teacher Build layers of understanding Have simple explanation of assertions and their use to support simple programming tasks, including debugging erroneous programs. 0 50 50 75
173 teach.layering Teacher Build layers of understanding Support the ability for advanced uses of contracts to be distributed across many different courses in a C++-focused computer science curriculum. 0 50 50 75 /50

N4820 and P1429 provide the least advanced features, but all of the proposals allow for basic contract use to be done (default level contract annotations) without any knowledge of the more advanced options that might be available.

174 compiler.benice Compiler Developer Deliver best experience to my customers Maximize implementation freedom by limiting what is strictly required by the standard 0 40 40 75

The explicit specification of build modes seems to be seen as highly restrictive by compiler vendors, and the less specific the standard is about that aspect of the facility the more this user base seems to be satisfied.

175 compiler.best Compiler Developer Deliver the best implementation Have a clear and simple specification that meets clear need 0 15 75 75

N4820 had many open questions about its specification where it had diverged from the original contract proposals. The semantic presentation in P1429 and P1607 sought to be very precise about what was expected of program behavior for any given contract.

176 large.complex Large Codebase Developer Debug complex issues Have composable and fine grained control over which checks are run, without requiring source code changes. Specifically the checks for only one function or some grouping of functions 25 0 0 25
177 large.critical Large Codebase Developer Enable/Disable checking on critical/hot paths Control whether checks are run based on where they are being called from 0 0 0 0

A macro based facility could build this form of subsetting with a great deal of effort, though callsite based checking does not seem feasible in any macro based facility. N4820 and P1429 provide no fine grained control of checks.

178 large.stillmacros Large Codebase Owner Modernize my code base Have my existing macro-based facilities interoperate smoothly with standardized contracts so I can do the migration gradually 0 0 0 75

Only by mapping to literal semantics could a more advanced contract facility be able to maintain behaviors while still using the same underlying facility that the language provides.

179 large.observation Large Codebase Owner Introduce new contracts into an existing system Have failed individual checks from existing code optionally warn instead of hard stop 25 25 25 75
180 large.introduction Large Codebase Owner Introduce new contracts into an existing system Have failed checks from a new library optionally warn instead of hard stop 25 25 50 75
181 large.newenvironment Large Codebase Owner Introduce new elements into a contracts based system Have failed checks caused by a change in environment optionally warn instead of hard stop 25 25 50 75
182 large.newcompiler Large Codebase Owner Introduce new elements into a contracts based system Have failed checks caused by a change in compiler optionally warn instead of hard stop 25 25 50 75

N4820 and P1429 provide a continuation mode to be able to make this decision at a global (or translation unit) scope. P1607 provides the ability to do this per-contract.

183 large.separability Large Codebase Owner Introduce new parameters or invariants into a contracts based system Be able to include distinct clauses for each parameter or invariant with their own individual failure or build controls 25 75 75 75

All of the language proposals allowed for multiple distinct annotations on a single function.

184 large.nogoingback Large Codebase Owner Prevent regressions Have trusted contracts fail fast and hard stop 25 0 10 75

The global controls of N4820 and P1429 limit the ability to enforce only those checks that are trusted, and provide no natural way to mix some continuing contracts with some non-continuing contracts. (P1429 would allow this by assigning different semantics to audit and default level contracts, but that would conflict with the intended distinction between those levels based on cost of checking.)

185 large.scalability Large Codebase Owner Scale violation handling Be able to log violations in my organization specific format 25 90 90 90

All of the proposals with a global pluggable violation handler allow this form of customization, though it is not required by any that a compiler actually allow the customization of the violation handler.

186 large.simulation.disable Large Codebase Owner Allow simulation or post-mortem testing of known failure modes Optionally disable checking on a subset of individual annotations 25 0 0 25
187 large.simulation.enable Large Codebase Owner Allow simulation or post-mortem testing of known failure modes Optionally allow checking of a subset of individual annotations to fail and access its recovery path 25 0 0 25
188 large.simulation.ignore Large Codebase Owner Allow simulation or post-mortem testing of known failure modes Optionally allow checking of a subset of individual annotations to fail and continue failing 25 0 0 25

Subsets of annotations can be called out with macro-based solutions, but not with the global controls of N4820 or P1429.

189 large.perfcontrol.build Large Codebase Owner Manage performance cost Constrain the set of built time checks according to their performance overhead 0 25 25 20
190 large.perfcontrol.runtime Large Codebase Owner Manage performance cost Constrain the set of runtime checks according to their performance overhead 0 50 50 40

The language proposals had minimal control over build-time checking, but were focused on doing any constraining based on the cost of the check.

191 large.narrowing Large Codebase Owner Tune contract width in complex system Be able to narrow individual contract so it fails in testing not in production 25 0 0 50

A P1607 contract can have a macro to control individual semantics and go through a lifecycle where it is checked or enforced in testing but left ignored in production. Without global control, this cannot be done with N4820 or P1429.

192 embedded.nochecking Small Machine Developer Minimize executable footprint Remove all checking and diagnostic (eg. source location) overhead entirely from the final binary 25 50 50 50

The language based proposals allow for the removal of checking without

193 embedded.nologging Small Machine Developer Minimize executable footprint Remove all logging and diagnostic (but not checking) overhead from the final binary 25 10 10 10
194 embedded.minimize Small Machine Developer Minimize executable footprint Remove all but the most important diagnostic overhead from the final binary 25 0 0 0

None of the proposals allow for total removal of logging information from the generated code, while a macro based facility could support that option.

It would conceivable be possible for link time optimization to recognize that a violation handler made no use of source information/did no logging and then it would be able to remove that source information as well, but this would have significant compile time overhead on a system.

195 wg21.everythingelse Language Developer Interoperate with Contracts Have a clear way to understand how contracts will interact with the standard library 0 0 0 0
196 wg21.otherfeatures Language Developer Extend contracts beyond pre/post conditions on functions Be able to use contract-like syntax on past or present runtime checkable language features such as switches, pattern matching, etc. or what might happen on signed integer overflow, etc. This might allow configuration of trapping, logging, or assuming in other areas of language UB. 0 0 0 0

None of the proposed solutions began integration with the rest of the standard, though they would have facilitated it in various ways.


Conclusion

This is a lot of information to digest, so it might help to be able to get some overview numbers on how the different proposals relate to one another. There are endless ways to do this, and we make no attempt to be complete in this analysis, but we will present some approaches that might be useful.

Proposal Score Score W/Macros
N4842 0.000% 22.041%
N4820 31.454% 31.454%
P1429 37.908% 37.908%
P1607 42.321% 43.087%
Proposal Score Score W/Macros
N4842 0.000% 24.683%
N4820 38.306% 38.306%
P1429 44.703% 44.703%
P1607 48.847% 49.527%
Proposal Score Score W/Macros
N4842 0.000% 28.419%
N4820 48.156% 48.156%
P1429 54.359% 54.359%
P1607 57.940% 58.634%

Note that these are not intended to produce a complete measure of those proposals, but simply as an example of how they might be compared. These totals are not a good measure of which proposal is intrinsicly better, but the changes to these totals from any individual proposal should be considered relevant when trying to understand how all users might benefit from any perticular change.