104 lines
7.5 KiB
HTML
104 lines
7.5 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<title>Major differences - Boost.Outcome documentation</title>
|
|
<link rel="stylesheet" href="../css/boost.css" type="text/css">
|
|
<meta name="generator" content="Hugo 0.52 with Boostdoc theme">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
|
|
|
<link rel="icon" href="../images/favicon.ico" type="image/ico"/>
|
|
<body><div class="spirit-nav">
|
|
<a accesskey="p" href="../experimental/map.html"><img src="../images/prev.png" alt="Prev"></a>
|
|
<a accesskey="u" href="../experimental.html"><img src="../images/up.png" alt="Up"></a>
|
|
<a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../experimental/status_result.html"><img src="../images/next.png" alt="Next"></a></div><div id="content">
|
|
<div class="titlepage"><div><div><h1 style="clear: both">Major differences</h1></div></div></div>
|
|
<p>The major design differences between <code><system_error></code> and proposed <code><system_error2></code> are
|
|
as follows:</p>
|
|
|
|
<ol>
|
|
<li><p><code>experimental::status_code<DomainType></code> can represent warnings
|
|
and form-of-success codes as well as failure codes. <code>experimental::errored_status_code<DomainType></code>
|
|
is more similar to <code>std::error_code</code>, in that it can only represent failures
|
|
(this is enforced by C++ 20 contract or runtime assertion check).</p></li>
|
|
|
|
<li><p>The code’s domain implementation defines the payload type to be transported around by
|
|
<code>experimental::status_code<DomainType></code>, rather than it being
|
|
hardcoded to <code>int</code> as in <code>std::error_code</code>. The payload type can be anything
|
|
you like, including non-trivially-copyable, move-only, complex etc types.</p>
|
|
|
|
<p>This facility is extremely useful. Extra failure metadata such as stack
|
|
backtraces can be returned, for example. You can absolutely vary the payload
|
|
depending on whether <code>NDEBUG</code> or <code>_DEBUG</code> is defined, too.</p></li>
|
|
|
|
<li><p>If your domain defines a payload type which is trivially copyable or
|
|
move relocating<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>, it gains an implicit convertibility to a move-only
|
|
<code>experimental::status_code<erased<T>></code> where <code>T</code> is another
|
|
trivially copyable or move relocating type. This permits global headers
|
|
to use a single, common, type erased, status code type which is highly
|
|
desirable for code bases of any complexity. However, unlike <code>std::error_code</code>,
|
|
which fulfils the exact same role in <code><system_error></code> based code, the type
|
|
erased payload can be bigger than the hardcoded <code>int</code> in <code>std::error_code</code>.</p>
|
|
|
|
<p>This facility is also extremely useful, as extra failure metadata can be
|
|
type erased, transported through code with no knowledge of such things,
|
|
and the original type with failure metadata resurrected at the handling point.
|
|
Indeed P1095 proposed <code>std::error</code> is a type alias to
|
|
<code>experimental::status_code<erased<intptr_t>></code>, and it can transport erased
|
|
<code>std::exception_ptr</code> instances, POSIX error codes, and much more besides.</p></li>
|
|
|
|
<li><p>Equality comparisons between status code’s with non-identical domains are
|
|
always <b><em>semantic</em></b> i.e. are they semantically equivalent, rather than exactly
|
|
equal? This mirrors when you compare <code>std::error_code</code> to a <code>std::error_condition</code>,
|
|
but as there is no equivalent for the latter in <code><system_error2></code>, this means
|
|
that when you see the code:</p>
|
|
<div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="k">if</span><span class="p">(</span><span class="n">code1</span> <span class="o">==</span> <span class="n">code2</span><span class="p">)</span> <span class="p">...</span>
|
|
</code></pre></div>
|
|
<p>… you can be highly confident that this is an inexact, semantic, match operation.
|
|
The same code under <code><system_error></code> is highly ambiguous as to whether exact
|
|
or inexact comparison is being performed (after all, all there is is “<code>code1 == code2</code>”,
|
|
so it depends on the types of <code>code1</code> and <code>code2</code> which usually is not obvious).</p>
|
|
|
|
<p>The ambiguity, and high cognitive load during auditing <code><system_error></code> code for correctness, has
|
|
led to many surprising and unexpected failure handling bugs during the past
|
|
decade in production C++.</p></li>
|
|
|
|
<li><p><code><system_error2></code>, being a new design, has all-constexpr construction and
|
|
destruction which avoids the need for static global variables, as <code><system_error></code>
|
|
has. Each of those static global variables requires an atomic fence just in
|
|
case it has not been initialised, thus every retrieval of an error category bloats
|
|
code and inhibits optimisation, plus makes the use of custom error code categories
|
|
in header-only libraries unreliable. Boost.System has replicated the all-constexpr
|
|
construction and destruction from <code><system_error2></code>, and thus now has similar
|
|
characteristics in this regard.</p></li>
|
|
|
|
<li><p>Finally, this is a small but important difference. Under <code><system_error></code>,
|
|
this extremely common use case is ambiguous:</p>
|
|
<div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="k">if</span><span class="p">(</span><span class="n">ec</span><span class="p">)</span> <span class="p">...</span>
|
|
</code></pre></div>
|
|
<p>Does this code mean “if there was an error?”, or “if the error code is set?”,
|
|
or “is the error code non-zero?”. The correct answer according to the standard is the last choice, but
|
|
a quick survey of open source <code><system_error></code> based code on github quickly
|
|
demonstrates there is widespread confusion regarding correct usage.</p>
|
|
|
|
<p><code><system_error2></code> solves this by removing the boolean test entirely. One
|
|
now writes <code>if(sc.success()) ...</code>, <code>if(sc.failure()) ...</code>, <code>if(sc.empty()) ...</code>
|
|
and so on, thus eliminating ambiguity.</p></li>
|
|
</ol>
|
|
<div class="footnotes">
|
|
|
|
<hr />
|
|
|
|
<ol>
|
|
<li id="fn:1"><a href="http://wg21.link/P1029">Move relocating is not in the standard, nor has been reviewed by WG21 yet</a>. It is defined to be a type whose move constructor <code>memcpy()</code>’s the bits from source to destination, followed by <code>memcpy()</code> 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 <code>std::vector<T></code>, <code>std::shared_ptr<T></code>, and <code>std::exception_ptr</code>.
|
|
<a class="footnote-return" href="#fnref:1"><sup>[return]</sup></a></li>
|
|
</ol>
|
|
</div>
|
|
|
|
|
|
</div><p><small>Last revised: February 05, 2019 at 17:14:18 UTC</small></p>
|
|
<hr>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="../experimental/map.html"><img src="../images/prev.png" alt="Prev"></a>
|
|
<a accesskey="u" href="../experimental.html"><img src="../images/up.png" alt="Up"></a>
|
|
<a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../experimental/status_result.html"><img src="../images/next.png" alt="Next"></a></div></body>
|
|
</html>
|