<html><head><meta charset="UTF-8">
<title>Wording for Networking PDTS ballot comment resolutions</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}
  #hidedel:checked ~ * del, #hidedel:checked ~ * del * { display:none; visibility:hidden }
  </style>
</head><body>
<table id="boilerplate">
<tr><td>Document number</td><td>P0742R0</td></tr>
<tr><td>Date</td><td>2017-07-14</td></tr>
<tr><td>Project</td><td>Programming Language C++, Library Working Group</td></tr>
<tr><td>Reply-to</td><td>Jonathan Wakely &lt;cxx&#x40;kayari.org&gt;</td></tr>
</table><hr>
<h1>Wording for Networking PDTS ballot comment resolutions</h1>
<h2>Introduction</h2>

<p>This paper presents proposed changes in response to some of the National Body comments for PDTS 19216 from <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4643.pdf">N4643</a>.</p>

<h2>Changes</h2>

<h3>NB comment 007 (GB-2)</h3>

<blockquote><p>"No constructor ... shall exit via an exception" over-specification.
This is probably a copy/paste error introduced when this text was copied from the standard (I believe from [allocator.requirements]).
The intent is only that copy and move constructors shall not throw, and I think that is already covered by "copy operation, move operation". Other constructors not covered by the ProtoAllocator requirements should be allowed to throw.</p>

<p><strong>Proposed change:</strong>
Delete "constructor," so that the sentence reads "No comparison operator, copy operation, move operation, or swap operation on these types shall exit via an exception."</p></blockquote>

<p>The comment is correct, the text was copied from the requirements on allocator pointer types, and imposes restrictions on proto-allocators that are not present on C++ allocators (see <a href="https://wg21.link/lwg2455">LWG 2455</a>). For consistency with the allocator requirements in the IS, non-copy/move constructors should both be allowed to throw.</p>

<h3>NB comment 009 (GB-4)</h3>

<blockquote><p>"No constructor ... shall exit via an exception" over-specification.
This is probably a copy/paste error introduced when this text was copied from the standard (I believe from [allocator.requirements]).
The intent is only that copy and move constructors shall not throw, and I think that is already covered by "copy operation, move operation". Other constructors not covered by the Executor requirements should be allowed to throw.</p>

<p><strong>Proposed change:</strong>
Delete "constructor," so that the sentence reads "No comparison operator, copy operation, move operation, swap operation, or member functions context, on_work_started, and on_work_finished on these types shall exit via an exception."</p></blockquote>

<p>Similar to 007.</p>

<h3>NB comment 010 (GB-5)</h3>

<blockquote><p>Executor requirements table refers to undefined name 'Func'.
The Executor requirements table entries for 'dispatch', 'post' and 'defer' refer to an undefined name 'Func', in 'DECAY_COPY(forward<Func>(f))'. This name is not listed in the paragraph preceding the table.</p>

<p><strong>Proposed change:</strong>
Fix the requirements table so that either the name 'Func' is defined, or so that the requirements for 'dispatch', 'post' and 'defer' are specified without referring to this type.</p></blockquote>

<p>Define <code>Func</code> and rephrase slightly to avoid using "callable" which is a term of art.</p>

<p>I also noticed that the dispatch functions require an Allocator,
but this is a perfect example of something that only needs a proto-allocator,
because it will be rebound anyway. I fixed that as a drive-by.</p>

<h3>NB comment 013 (US-12)</h3>

<blockquote><p>"user-defined function objects" - user defined is possibly over-specification. In other parts of the TS it refers to types not specified by this TS. If there are function objects defined in the standard, they should also be destroyed.</p>

<p><strong>Proposed change:</strong> remove "user-defined"</p></blockquote>

<p>Accept the change.</p>

<h3>NB comment 020 (GB-11)</h3>

<blockquote><p>Consider adding noexcept to buffer sequence requirements
[buffer.reqmts.mutablebuffersequence], [buffer.reqmts.constbuffersequence], [buffer.seq.access]</p>

<p><strong>Proposed change:</strong>
Adding "Shall not exit via an exception." to the the requirements for net::buffer_sequence_begin(x) and 'net::buffer_sequence_end(x).<br/>
Requiring that the conversion of the iterator value type to const_buffer or mutable_buffer should not exit via exception.<br/>
(And perhaps place the same requirement on the iterator traversal and dereference too, although I'm not sure if this is already implied elsewhere in the standard?)<br/>
Adding noexcept to the buffer sequence access functions.<br/>
The current implementation in asio assumes that these never throw, and in general I think low level buffer operations should not throw.</p></blockquote>

<p>It seems reasonable to forbid these operations from throwing, and therefore
good to add <code>noexcept</code> to the access functions (which have wide contracts).</p>

<p>Casey Carter also noticed that the <strong>return type</strong> column requires the value type to be convertible to the buffer,
but it should be the reference type.</p>

<h3>NB comment 024 (GB-13)</h3>

<blockquote><p>The derived socket types basic_datagram_socket and basic_stream_socket should specify that their native_handle_type is the same as basic_socket::native_handle_type.</p>

<p><strong>Proposed change:</strong> Add such specification</p></blockquote>

<p>This ensures that the derived class constructor can pass a native handle argument to the base class constructor.</p>

<p>Additionally, the PDTS is missing wording to say that when effects are described as if by POSIX <code>foobar(native_handle())</code> that it is assumed that <code>native_handle()</code> returns an <code>int</code>!</p>

<h3>NB comment 028 (GB-17)</h3>

<blockquote><p>[socket.acceptor.cons] move ctor missing postcondition.
The postconditions for the basic_socket_acceptor move ctor don't have any postconditions on native_handle().</p>

<p><strong>Proposed change:</strong>
Add "native_handle() returns the prior value of rhs.native_handle()."</p></blockquote>

<p>Accept the change.</p>

<h3>NB comment 029 (GB-18)</h3>

<blockquote><p>[socket.streambuf.cons] Add missing error() postconditions.
The basic_socketstreambuf constructors do not give any postconditions for the ec_ member.</p>

<p><strong>Proposed change:</strong>
Add "and !error()" to paragraphs 2 and 4. Add "error() == rhs_p.error()" and "!rhs_a.error()" to paragraph 6.</p></blockquote>

<p>Accept the change.</p>

<h3>NB comment 030 (GB-19)</h3>

<blockquote><p>[socket.streambuf.cons] Cover changes to rhs in operator= effects.
The assignment operator for basic_socketstreambuf doesn't state the effects on the RHS.</p>

<p><strong>Proposed change:</strong>
Change "*this has the observable state it would have had if it had been move constructed from rhs" to "*this and rhs have the observable state they would have had if *this had been move constructed from rhs"</p></blockquote>

<p>Accept the change.</p>

<h3>NB comment 033 (GB-20)</h3>

<blockquote><p>Shorten ip::resolver_errc enumerator names.
These enumerator names predate enum classes as a language feature and were so named to eliminate likely name clashes with other entities
in the same namespace. The enumerator "host_not_found_try_again" is particularly long and could be shortened.</p>

<p><strong>Proposed change:</strong>
Rename the enumerator "host_not_found_try_again" to "try_again".</p></blockquote>

<p>This was discussed by LEWG: "Needs a paper looking at the whole set of enum names systematically". This is that paper.</p>

<p>The PDTS contains the following enumeration types and enumerators:</p>

<pre><code>    enum class fork_event {
      prepare,
      parent,
      child
    };

    enum class stream_errc {
      eof = an implementation defined non-zero value ,
      not_found = an implementation defined non-zero value
    };

    enum class socket_errc {
      already_open = an implementation defined non-zero value ,
      not_found = an implementation defined non-zero value
    };

    enum class resolver_errc {
      host_not_found = an implementation-defined non-zero value , // EAI_NONAME
      host_not_found_try_again = an implementation-defined non-zero value , // EAI_AGAIN
      service_not_found = an implementation-defined non-zero value // EAI_SERVICE
    };
</code></pre>

<p>Of these, only the enumerators for <code>resolver_errc</code> are lengthy. As there are
two different "not found" errors they can't reasonably be shortened to simply
<code>not_found</code>. They could conceivably be <code>no_name</code> and <code>bad_service</code>, but the current names seem just as good to me.</p>

<p>That leaves just <code>host_not_found_try_again</code>, which is what the NB comment
objects to. POSIX defines the <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html">EAI_AGAIN</a> error as "The name could not be resolved at this time. Future attempts may succeed." I think <code>try_again</code> is a good fit for that.</p>

<h2>Proposed Wording</h2>

<p>All changes are relative to <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4656.pdf">N4656</a>.</p>

<p>Modify 13.2.1 [async.reqmts.proto.allocator] paragraph 1 as shown:</p>

<blockquote><p>A type <code>A</code> meets the proto-allocator requirements if <code>A</code> is <code>CopyConstructible</code> (C++Std [copyconstructible]), <code>Destructible</code> (C++Std [destructible]), and <code>allocator_traits&lt;A&gt;::rebind_alloc&lt;U&gt;</code> meets the allocator requirements (C++Std [allocator.requirements]), where <code>U</code> is an object type. <em>[Note:</em> For example,
<code>std::allocator&lt;void&gt;</code> meets the proto-allocator requirements but not the allocator requirements. <em>--end note]</em> No <del>constructor,</del> comparison operator, copy operation, move operation, or swap operation on these
types shall exit via an exception.</p></blockquote>

<p>Modify 13.2.2 [async.reqmts.executor] paragraph 3 as shown:</p>

<blockquote><p>No <del>constructor,</del> comparison operator, copy operation, move operation, swap operation, or member functions <code>context</code>, <code>on_work_started</code>, and <code>on_work_finished</code> on these types shall exit via an exception.</p></blockquote>

<p>Modify 13.2.2 [async.reqmts.executor] paragraph 6 as shown:</p>

<blockquote><p>In Table 4, <code>x1</code> and <code>x2</code> denote (possibly const) values of type <code>X</code>, <code>mx1</code> denotes an xvalue of type <code>X</code>, <code>f</code> denotes a <ins>function object of</ins> <code>MoveConstructible</code> (C++Std [moveconstructible]) <del>function object</del> <ins>type <code>Func</code> such that <code>f()</code> is a valid expression</ins> <del>callable with zero arguments</del>, <code>a</code> denotes a (possibly const) value of type <code>A</code> meeting the <code><ins>Proto</ins>Allocator</code> requirements (<del>C++Std [allocator.requirements]</del> <ins>12.2.1 [async.reqmts.proto.allocator]</ins>), and <code>u</code> denotes an identifier.</p></blockquote>

<p>Modify 13.2.4  [async.reqmts.service] paragraph 5 as shown:</p>

<blockquote><p>A service's <code>shutdown</code> member function shall destroy all copies of <del>user-defined</del> function objects that are held by the service.</p></blockquote>

<p>Modify 16.1 [buffer.synop] to add <code>noexcept</code> to the signatures:</p>

<blockquote><p><em>// buffer sequence access:</em></p></blockquote>

<pre><code>      const mutable_buffer* buffer_sequence_begin(const mutable_buffer&amp; b)<ins> noexcept</ins>;
      const const_buffer* buffer_sequence_begin(const const_buffer&amp; b)<ins> noexcept</ins>;
      const mutable_buffer* buffer_sequence_end(const mutable_buffer&amp; b)<ins> noexcept</ins>;
      const const_buffer* buffer_sequence_end(const const_buffer&amp; b)<ins> noexcept</ins>;
      template&lt;class C&gt; auto buffer_sequence_begin(C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.begin());
      template&lt;class C&gt; auto buffer_sequence_begin(const C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.begin());
      template&lt;class C&gt; auto buffer_sequence_end(C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.end());
      template&lt;class C&gt; auto buffer_sequence_end(const C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.end());
</code></pre>

<p>Modify 16.2.1 [buffer.reqmts.mutablebuffersequence] Table 12 by adding to the third column of the first row:</p>

<blockquote><p><strong>expression</strong></p></blockquote>

<p><code>net::buffer_sequence_begin(x)</code><br/>
<code>net::buffer_sequence_end(x)</code></p>

<blockquote><p><strong>return type</strong></p>

<p>An iterator type meeting the requirements for bidirectional iterators
(C++Std [bidirectional.iterators]) whose <del>value</del><ins>reference</ins> type is convertible to <code>mutable_buffer</code>.</p>

<p><strong>assertion/note/pre/post-condition</strong>:</p>

<p><ins>For a dereferenceable iterator, no increment, decrement, or dereference operation, or conversion of the reference type to <code>mutable_buffer</code>, shall exit via an exception.</ins></p></blockquote>

<p>Modify 16.2.2 [buffer.reqmts.constbuffersequence] Table 13 by adding to the third column of the first row:</p>

<blockquote><p><strong>expression</strong></p></blockquote>

<p><code>net::buffer_sequence_begin(x)</code><br/>
<code>net::buffer_sequence_end(x)</code></p>

<blockquote><p><strong>return type</strong></p>

<p>An iterator type meeting the requirements for bidirectional iterators
(C++Std [bidirectional.iterators]) whose <del>value</del><ins>reference</ins> type is convertible to <code>const_buffer</code>.</p>

<p><strong>assertion/note/pre/post-condition</strong>:</p>

<p><ins>For a dereferenceable iterator, no increment, decrement, or dereference operation, or conversion of the reference type to <code>const_buffer</code>, shall exit via an exception.</ins></p></blockquote>

<p>Modify 16.7 [buffer.seq.access] to add <code>noexcept</code> to the signatures:</p>

<pre><code>        const mutable_buffer* buffer_sequence_begin(const mutable_buffer&amp; b)<ins> noexcept</ins>;
        const const_buffer* buffer_sequence_begin(const const_buffer&amp; b)<ins> noexcept</ins>;
</code></pre>

<blockquote><p>-1- <em>Returns:</em> <code>std::addressof(b)</code>.</p></blockquote>

<pre><code>        const mutable_buffer* buffer_sequence_end(const mutable_buffer&amp; b)<ins> noexcept</ins>;
        const const_buffer* buffer_sequence_end(const const_buffer&amp; b)<ins> noexcept</ins>;
</code></pre>

<blockquote><p>-2- <em>Returns:</em> <code>std::addressof(b) + 1</code>.</p></blockquote>

<pre><code>        template&lt;class C&gt; auto buffer_sequence_begin(C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.begin());
        template&lt;class C&gt; auto buffer_sequence_begin(const C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.begin());
</code></pre>

<blockquote><p>-3- <em>Returns:</em> <code>c.begin()</code>.</p></blockquote>

<pre><code>        template&lt;class C&gt; auto buffer_sequence_end(C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.end());
        template&lt;class C&gt; auto buffer_sequence_end(const C&amp; c)<ins> noexcept</ins> -&gt; decltype(c.end());
</code></pre>

<blockquote><p>-4- <em>Returns:</em> <code>c.end()</code>.</p></blockquote>

<p>Add a new paragraph to 18.2.3 [socket.reqmts.native] after paragraph 1:</p>

<blockquote><p><ins>-2- When an operation has its effects specified as if by passing the result of <code>native_handle()</code> to a POSIX function the effect is as if
<code>native_handle_type</code> is the type <code>int</code>.</ins></p></blockquote>

<p>Add a new paragraph to 18.7 [socket.dgram] after paragraph 5:</p>

<blockquote><p><ins>-6- If <code>native_handle_type</code> and <code>basic_socket&lt;Protocol&gt;::native_handle_type</code> are both defined then they name the same type.</ins></p></blockquote>

<p>Add a new paragraph to 18.8 [socket.stream] after paragraph 5:</p>

<blockquote><p><ins>-6- If <code>native_handle_type</code> and <code>basic_socket&lt;Protocol&gt;::native_handle_type</code> are both defined then they name the same type.</ins></p></blockquote>

<p>Modify 18.9.1 [socket.acceptor.cons] paragraph 10 as shown:</p>

<blockquote><p>-10- <em>Postconditions:</em></p>

<ul>
<li><p><code>get_executor() == rhs.get_executor()</code>.</p></li>
<li><p><code>is_open()</code> returns the same value as <code>rhs.is_open()</code> prior to the constructor invocation.</p></li>
<li><p><code>non_blocking()</code> returns the same value as <code>rhs.non_blocking()</code> prior to the constructor invocation.</p></li>
<li><p><code>enable_connection_aborted()</code> returns the same value as <code>rhs.enable_connection_aborted()</code> prior to the constructor invocation.</p></li>
<li><p><ins><code>native_handle()</code> returns the same value as <code>rhs.native_handle()</code> prior to the constructor invocation.</ins></p></li>
<li><p><code>protocol_</code> is equal to the prior value of <code>rhs.protocol_</code>.</p></li>
<li><p><code>rhs.is_open() == false</code>.</p></li>
</ul>
</blockquote>

<p>Modify 19.1.1 [socket.streambuf.cons] as shown:</p>

<blockquote><p>-2- <em>Postconditions:</em> <code>expiry() == time_point::max()</code> <ins>and <code>!error()</code></ins>.</p>

<p>[...]</p>

<p>-4- <em>Postconditions:</em> <code>expiry() == time_point::max()</code> <ins>and <code>!error()</code></ins>.</p>

<p>[...]</p>

<p>-6- <em>Postconditions:</em> Let <code>rhs_p</code> refer to the state of <code>rhs</code> just prior to this construction and let <code>rhs_a</code> refer
to the state of <code>rhs</code> just after this construction.</p>

<ul>
<li><p><code>is_open() == rhs_p.is_open()</code></p></li>
<li><p><code>rhs_a.is_open() == false</code></p></li>
<li><p><ins><code>error() == rhs_p.error()</code></ins></p></li>
<li><p><ins><code>!rhs_a.error()</code></ins></p></li>
<li><p><code>expiry() == rhs_p.expiry()</code></p></li>
<li><p><code>rhs_a.expiry() == time_point::max()</code></p></li>
</ul>


<p>[...]</p></blockquote>

<pre><code>        basic_socket_streambuf&amp; operator=(basic_socket_streambuf&amp;&amp; rhs);
</code></pre>

<blockquote><p>-8- <em>Effects:</em> Calls <code>this-&gt;close()</code> then moves the state from <code>rhs</code>. After the move assignment <code>*this</code> <ins>and <code>rhs</code> have</ins> <del>has</del> the
observable state <ins>they</ins> <del>it</del> would have had if <ins><code>*this</code></ins> <del>it</del> had been move constructed from <code>rhs</code>.</p></blockquote>

<p>Modify 21.1 [internet.synop] as shown:</p>

<blockquote><p><code>enum class resolver_errc {</code><br/>
  <code>host_not_found =</code> <em>an implementation-defined non-zero value</em> <code>,</code> // EAI_NONAME<br/>
  <del><code>host_not_found_</code></del><code>try_again =</code> <em>an implementation-defined non-zero value</em> <code>,</code> // EAI_AGAIN<br/>
  <code>service_not_found =</code> <em>an implementation-defined non-zero value</em> // EAI_SERVICE
  <code>};</code></p></blockquote>
</body></html>
