<html><head><meta charset="UTF-8">
<title>Make std::memory_order a scoped enumeration</title>
  <style type='text/css'>
  body {font-variant-ligatures: none;}
  p {text-align:justify}
  li {text-align:justify}
  blockquote.note, div.note
  {
          background-color:#E0E0E0;
          padding-left: 15px;
          padding-right: 15px;
          padding-top: 1px;
          padding-bottom: 1px;
  }
  p code {color:navy}
  ins p code {color:#00A000}
  p ins code {color:#00A000}
  p del code {color:#A00000}
  ins {color:#00A000}
  del {color:#A00000}
  table#boilerplate { border:0 }
  table#boilerplate td { padding-left: 2em }
  table.bordered, table.bordered th, table.bordered td {
    border: 1px solid;
    text-align: center;
  }
  ins.block {color:#00A000; text-decoration: none}
  del.block {color:#A00000; text-decoration: none}
  </style>
</head><body>
<table id="boilerplate">
<tr><td>Document number</td><td>P0439R0</td></tr>
<tr><td>Date</td><td>2016-10-06</td></tr>
<tr><td>Project</td><td>Programming Language C++, Library Evolution Working Group, SG1</td></tr>
<tr><td>Reply-to</td><td>Jonathan Wakely &lt;cxx&#x40;kayari.org&gt;</td></tr>
</table><hr>
<h1>Make std::memory_order a scoped enumeration</h1>
<h2>Abstract</h2>

<p>I propose changing <code>std::memory_order</code> to be a scoped enumeration type, in
order to improve type safety and support more idiomatic C++ syntax.</p>

<h2>Background</h2>

<p>The enumeration type <code>std::memory_order</code> is defined in 29.3 [atomics.order] as:</p>

<pre><code>  namespace std {
    typedef enum memory_order {
      memory_order_relaxed, memory_order_consume, memory_order_acquire,
      memory_order_release, memory_order_acq_rel, memory_order_seq_cst
    } memory_order;
  }
</code></pre>

<p>This style was used so the definition would be compatible with C, but that
noble aim failed with the introduction of <code>_Atomic</code> as a type qualifier in C11.
In any case, the fact it's defined in namespace <code>std</code> means it is a distinct
type from an equivalent type defined in the global namespace.</p>

<p>The style of specification (as a typedef for an enumeration type of the same
name) is entirely unnecessary in C++, and the naming of the enumerators is an
unfortunate wart. Let's address it.</p>

<h2>What <code>memory_order</code> would look like in idiomatic C++</h2>

<p>There is no reason to continue specifying it as a typedef-declaration, and we
should editorially change the specification to:</p>

<pre><code>  namespace std {
    <del>typedef </del>enum memory_order {
      memory_order_relaxed, memory_order_consume, memory_order_acquire,
      memory_order_release, memory_order_acq_rel, memory_order_seq_cst
    }<del> memory_order</del>;
</code></pre>

<p>But let's not stop there. If I was designing this type today I would not have
named the enumerators with the type name as a prefix, I would have used a
scoped enumeration type:</p>

<pre><code>    enum class memory_order {
      relaxed, consume, acquire, release, acq_rel, seq_cst
    };
</code></pre>

<p>To name an enumerator you would say <code>memory_order::acquire</code> instead of
<code>memory_order_acquire</code>, or following <code>using MO = std::memory_order;</code> you could
say <code>MO::acquire</code> instead.</p>

<p>More importantly, a scoped enumeration is more strongly typed, disallowing
implicit conversion to integers, and preventing nonsensical expressions such as
<code>memory_order_acquire|memory_order_release</code> (which could be mistakenly assumed
to be equivalent to <code>memory_order_acq_rel</code>) or <code>~memory_order_relaxed</code>.  A
scoped enumeration is a better match for the desired semantics of these
constants.</p>

<h2>Compatibility</h2>

<p>In order to maintain source compatibility we can declare inline variables
of the enumeration type with the existing names:</p>

<pre><code>    inline constexpr auto memory_order_relaxed = memory_order::relaxed;
    inline constexpr auto memory_order_consume = memory_order::consume;
    inline constexpr auto memory_order_acquire = memory_order::acquire;
    inline constexpr auto memory_order_release = memory_order::release;
    inline constexpr auto memory_order_acq_rel = memory_order::acq_rel;
    inline constexpr auto memory_order_seq_cst = memory_order::seq_cst;
</code></pre>

<p>This ensures that any source code using the existing names continues to
compile and has the same meaning.</p>

<p>In order to maintain binary compatibility the underlying type of the scoped
enumeration type should be left unspecified, so that implementations can set it
to match the underlying type that was previously chosen (either implicitly or
explicitly) for the unscoped enumeration type.</p>

<p>For the Itanium C++ ABI (and to the best of my knowledge the VC++ ABI) the
<code>memory_order</code> type is mangled the same whether it's a scoped or unscoped
enumeration type. I don't believe the proposed changes to the enumerator
names (and introduction of inline variables for the old names) can change
the mangled names of any symbols either. The old names were only enumerators,
so they are not lvalues and only their values (not names) can appear in
mangled names.</p>

<h2>Alternative</h2>

<p>Since C++11 it has been possible to refer to enumerators of unscoped
enumerations using the type name as a nested-name-qualifier. In order to
support <code>memory_order::seq_cst</code> we could simply add extra enumerators:</p>

<pre><code>    enum memory_order {
      memory_order_relaxed, memory_order_consume, memory_order_acquire,
      memory_order_release, memory_order_acq_rel, memory_order_seq_cst,
      relaxed = memory_order_relaxed,
      consume = memory_order_consume,
      acquire = memory_order_acquire,
      release = memory_order_release,
      acq_rel = memory_order_acq_rel,
      seq_cst = memory_order_seq_cst
    };
</code></pre>

<p>This doesn't have the type safety advantages of a scoped enumeration, and the
new enumerators would "leak" into the surrounding namespace, so would also be
visible as <code>std::seq_cst</code>.  This alternative would not be an improvement.</p>

<h2>Related Issues</h2>

<p><code>std::atomic_flag</code> is also defined as a typedef declaration, and relying on
the preprocessor for <code>ATOMIC_FLAG_INIT</code> is most foul.</p>

<h2>Proposed Wording</h2>

<pre><code>  namespace std {
    <del>typedef </del>enum <ins>class </ins>memory_order <ins>: unspecified </ins>{
      <del>memory_order_relaxed, memory_order_consume, memory_order_acquire,
      memory_order_release, memory_order_acq_rel, memory_order_seq_cst</del>
      <ins>relaxed, consume, acquire, release, acq_rel, seq_cst</ins>
    }<del> memory_order</del>;
    <ins>inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;</ins>
    <ins>inline constexpr memory_order memory_order_consume = memory_order::consume;</ins>
    <ins>inline constexpr memory_order memory_order_acquire = memory_order::acquire;</ins>
    <ins>inline constexpr memory_order memory_order_release = memory_order::release;</ins>
    <ins>inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;</ins>
    <ins>inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;</ins>
  }
</code></pre>

<blockquote><p>The enumeration <code>memory_order</code> specifies the detailed regular (non-atomic) memory synchronization order as defined in 1.10 and may provide for operation ordering. Its enumerated values and their meanings are as follows:
— <code>memory_order<del>_</del><ins>::</ins>relaxed</code>: no operation orders memory.
— <code>memory_order<del>_</del><ins>::</ins>release</code>, <code>memory_order<del>_</del><ins>::</ins>acq_rel</code>, and <code>memory_order<del>_</del><ins>::</ins>seq_cst</code>: a store operation per-
forms a release operation on the affected memory location.
— <code>memory_order<del>_</del><ins>::</ins>consume</code>: a load operation performs a consume operation on the affected memory
location. [<em>Note:</em> Prefer <code>memory_order<del>_</del><ins>::</ins>acquire</code>, which provides stronger guarantees than <code>memory_order<del>_</del><ins>::</ins>consume</code>. Implementations have found it infeasible to provide performance better than that of
<code>memory_order<del>_</del><ins>::</ins>acquire</code>. Specification revisions are under consideration. <em>— end note</em>]
— <code>memory_order<del>_</del><ins>::</ins>acquire</code>, <code>memory_order<del>_</del><ins>::</ins>acq_rel</code>, and <code>memory_order<del>_</del><ins>::</ins>seq_cst</code>: a load operation performs an acquire operation on the affected memory location.</p></blockquote>

<h2>Acknowledgments</h2>

<p>Thanks to Maurice Bos for helping to check the ABI consequences of the change.</p>
</body></html>
