1+++ 2title = "Major differences" 3weight = 20 4+++ 5 6The major design differences between `<system_error>` and proposed `<system_error2>` are 7as follows: 8 91. `experimental::status_code<DomainType>` can represent warnings 10and form-of-success codes as well as failure codes. `experimental::errored_status_code<DomainType>` 11is more similar to `std::error_code`, in that it can only represent failures 12(this is enforced by C++ 20 contract or runtime assertion check). 13 142. The code's domain implementation defines the payload type to be transported around by 15`experimental::status_code<DomainType>`, rather than it being 16hardcoded to `int` as in `std::error_code`. The payload type can be anything 17you like, including non-trivially-copyable, move-only, complex etc types. 18 19 This facility is extremely useful. Extra failure metadata such as stack 20backtraces can be returned, for example. You can absolutely vary the payload 21depending on whether `NDEBUG` or `_DEBUG` is defined, too. 22 233. If your domain defines a payload type which is trivially copyable or 24move relocating[^1], it gains an implicit convertibility to a move-only 25`experimental::status_code<erased<T>>` where `T` is another 26trivially copyable or move relocating type. This permits global headers 27to use a single, common, type erased, status code type which is highly 28desirable for code bases of any complexity. However, unlike `std::error_code`, 29which fulfils the exact same role in `<system_error>` based code, the type 30erased payload can be bigger than the hardcoded `int` in `std::error_code`. 31 32 This facility is also extremely useful, as extra failure metadata can be 33type erased, transported through code with no knowledge of such things, 34and the original type with failure metadata resurrected at the handling point. 35Indeed P1095 proposed `std::error` is a type alias to 36`experimental::status_code<erased<intptr_t>>`, and it can transport erased 37`std::exception_ptr` instances, POSIX error codes, and much more besides. 38 394. Equality comparisons between status code's with non-identical domains are 40always <b><em>semantic</em></b> i.e. are they semantically equivalent, rather than exactly 41equal? This mirrors when you compare `std::error_code` to a `std::error_condition`, 42but as there is no equivalent for the latter in `<system_error2>`, this means 43that when you see the code: 44 45 ```c++ 46 if(code1 == code2) ... 47 ``` 48 49 ... you can be highly confident that this is an inexact, semantic, match operation. 50The same code under `<system_error>` is highly ambiguous as to whether exact 51or inexact comparison is being performed (after all, all there is is "`code1 == code2`", 52so it depends on the types of `code1` and `code2` which usually is not obvious). 53 54 The ambiguity, and high cognitive load during auditing `<system_error>` code for correctness, has 55led to many surprising and unexpected failure handling bugs during the past 56decade in production C++. 57 585. `<system_error2>`, being a new design, has all-constexpr construction and 59destruction which avoids the need for static global variables, as `<system_error>` 60has. Each of those static global variables requires an atomic fence just in 61case it has not been initialised, thus every retrieval of an error category bloats 62code and inhibits optimisation, plus makes the use of custom error code categories 63in header-only libraries unreliable. Boost.System has replicated the all-constexpr 64construction and destruction from `<system_error2>`, and thus now has similar 65characteristics in this regard. 66 676. Finally, this is a small but important difference. Under `<system_error>`, 68this extremely common use case is ambiguous: 69 70 ```c++ 71 if(ec) ... 72 ``` 73 74 Does this code mean "if there was an error?", or "if the error code is set?", 75or "is the error code non-zero?". The correct answer according to the standard is the last choice, but 76a quick survey of open source `<system_error>` based code on github quickly 77demonstrates there is widespread confusion regarding correct usage. 78 79 `<system_error2>` solves this by removing the boolean test entirely. One 80now writes `if(sc.success()) ...`, `if(sc.failure()) ...`, `if(sc.empty()) ...` 81and so on, thus eliminating ambiguity. 82 83 84[^1]: [Move relocating is not in the standard, nor has been reviewed by WG21 yet](http://wg21.link/P1029). It is defined to be a type whose move constructor `memcpy()`'s the bits from source to destination, followed by `memcpy()` of the bits of a default constructed instance to source, and with a programmer-given guarantee that the destructor, when called on a default constructed instance, has no observable side effects. A surprising number of standard library types can meet this definition of move relocating, including `std::vector<T>`, `std::shared_ptr<T>`, and `std::exception_ptr`.