<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<style>
pre {font-family: "Consolas", "Lucida Console", monospace; margin-left:20pt; }
code {font-family: "Consolas", "Lucida Console", monospace; }
pre > i   { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
code > i  { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
pre > em  { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
code > em { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
dl > dt { font-style:italic; }
body { font-family: "Calibri" }
h1 { margin-top: 3ex; margin-bottom: 2ex  }
 /* h2 { margin-top: 9ex; margin-bottom: 3ex  }*/

@media (prefers-color-scheme: dark) {
	body { background: #111; color:  #ccc; }
	a { color:  #38f; }
	a:visited { color:  #a4d; }
	.sect { color:  #ccc; }
    del { text-decoration: line-through; color: #EE9999; }
    ins { text-decoration: underline; color: #99EE99; }
    blockquote.std    { color: #ccc; background-color: #2A2A2A;  border: 1px solid #3A3A3A;  padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;  color: #ccc; background-color: #221820;  border: 1px solid #332228;  padding-left: 0.5em; padding-right: 0.5em; ; }
    blockquote.stdins { text-decoration: underline;  color: #ccc; background-color: #182220;  border: 1px solid #223328; padding: 0.5em; }
    table { border: 1px solid #ccc; border-spacing: 0px;  margin-left: auto; margin-right: auto; }
}

@media (prefers-color-scheme: light) {
	body { background:  white; color: black; }
    del { text-decoration: line-through; color: #8B0040; }
    ins { text-decoration: underline; color: #005100; }
    blockquote.std    { color: #000000; background-color: #F1F1F1;  border: 1px solid #D1D1D1;  padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;  color: #000000; background-color: #FFEBFF;  border: 1px solid #ECD7EC;  padding-left: 0.5em; padding-right: 0.5em; ; }
    blockquote.stdins { text-decoration: underline;  color: #000000; background-color: #C8FFC8;  border: 1px solid #B3EBB3; padding: 0.5em; }
    table { border: 1px solid black; border-spacing: 1px;  margin-left: auto; margin-right: auto; }
}


.comment em { font-family: "Calibri"; font-style:italic; }
p.example   { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }
div.poll { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract  { margin-left: 2em; background-color: #F5F6A2;  border: 1px solid #E1E28E; }

p.function    { }
.attribute    { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

.editor { color: #4444BB; font-style: normal; background-color: #DDDDDD; }

tab { padding-left: 4em; }
tab3 { padding-left: 3em; }

.link { float: right; font-family: "Consolas", "Lucida Console", monospace; font-size:80% }


table.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
td.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
table.poll { border: 1px solid black; border-spacing: 0px;  margin-left: 0px; font-style: normal; }

th { text-align: left; vertical-align: top;  padding-left: 0.4em;  /*padding-right: 0.4em; border-bottom:1px dashed;*/ }
td { text-align: left;  padding-left: 0.4em; padding-right: 0.4em; /*border-right:1px dashed; */}
tr { border: solid; border-width: 1px 0; border-bottom:1px solid blue }


.revision   { /*color: #005599;*/ }
.grammar { list-style-type:none }

</style>

<title>The contract of sort()</title>

</head>
<body>  

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;</th><th> </th><td class="header">P3212R0</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;</th><th> </th><td class="header">2024-07-03</td>
  </tr>
  <tr>
    <th>Audience:&nbsp;&nbsp;</th><th> </th><td class="header">SG21, EWG, LEWG</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;</th><th> </th><td class="header">
        <address>Andrzej Krzemieński &lt;akrzemi1 at gmail dot com&gt;</address>
    </td>
  </tr>
</tbody></table>



<h1>The contract of <code>sort()</code></h1>

<p> This paper lists all parts of the contract of function template <code>std::sort</code>
    and demonstrates which parts thereof can be reflected with <em>contract assertions</em>
    proposed in <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2900r7.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński, &ldquo;Contracts for C++&rdquo;">[P2900R7]</a>
	(Contracts for C++) or with the envisioned their future additions. 
    This is an exercise to test how much of the Standard Library specification can be mapped onto
    contract assertions.
    </p>


<h2>1. The <em>plain language</em> contract of <code>sort()</code></h2> 

<p> We only select one function template declaration for analysis</p>

<pre>
template&lt;random_access_iterator I, 
         sentinel_for&lt;I&gt; S, 
         class Comp = ranges::less,
         class Proj = identity&gt;
  requires sortable&lt;I, Comp, Proj&gt;
  constexpr I
    ranges::sort(I first, S last, Comp comp = {}, Proj proj = {});
</pre> 

<p> This function has <em>plenty</em> of requirements that it imposes on the callers,
    of different kind, not counting the type-system (syntactic) ones.</p>
    
<p> First, it uses concepts. Concepts have both syntactic and semantic requirements.
    While syntactic requirements are type-system-checked by the compiler,
    the responsibility of satisfying the semantic requirements falls on the caller.
    There is a difference between <em>satisfying</em> syntactic requirements
    of a concept and <em>modeling</em> a concept.</p>

<p> For instance the passed iterator is required (among other things) to be <code>movable</code>.
    But how one can runtime-test if the move constructor actually moves? The only way to 
    test it would be to perform a copy.</p>
    
<p>Second, there are more complex concepts involved:</p>

<ul>
<li><code>regular_invocable</code></li>
<li><code>strict_weak_order</code></li>
<li><code>permutable</code></li>
</ul>

<p> This requires that function <code>comp</code> be <em>equality-preserving</em> 
    over the elements in range [<code>first</code>, <code>last</code>). Thus, it is ok if 
    <code>comp</code> does not guarantee the strict weak order for some values
    <code>x</code> and <code>y</code> as long as they are not both passed to <code>sort</code>.</p>
    
<p> Next come the range-specific requirements: [<code>first</code>, <code>last</code>) shall 
    be a valid range upon calling the function. The caller shall also make sure 
    that the range doesn't change while the algorithm is executed, for instance from anther thread. 
    </p>
    
<p> Finally, there are sort-specific guarantees offered by the function:</p>

<ul>
<li>the resulting range is sorted with respect to <code>comp</code> and <code>proj</code>,</li>
<li>the output range is a permutation of the input range,</li>
<li>the number of calls to <code>comp</code> and <code>proj</code> is &Oscr;(<var>N</var> log <var>N</var>), 
    where <var>N</var> is <code>last - first</code>.</li>
</ul>


<h2>2. Encoding in contract assertions</h2> 

<h3>2.1 Checking concept modeling?</h3>

<p> Checking if a given type models a concept is not possible in general. 
    As noted above, there is no Boolean predicate that would check if the
    value of the new object is the same as the original value of the moved-from object.
    Especially that the tested type may not provide a copy constructor or equality comparison.
    Also, even reflecting it in the interface of <code>sort</code> appears wrong.
    In order for the contract assertion to be useful, it should reflect the part of the contract
    that the author has reasons to believe could be violated.</p>

<p> It is more likely that a user will provide a predicate that does not model <code>strict_weak_order</code>.
    This one can be evaluated, although with a quadratic complexity:</p>

<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr bool 
  is_strict_weak_order(I first, S last, Comp comp = {}, Proj proj = {})
{
  for (I i = first; i != last; ++i)
    for (I j = first; j != last; ++j)
      if (not test_strict_weak_order(comp, proj(i), proj(j)))
        return false;
  return true;  
} 

template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {})
  pre(is_strict_weak_order(first, last, comp, proj));  
</pre> 

<p> Calling a quadratic algorithm of an otherwise &Oscr;(<var>N</var> log <var>N</var>) algorithm
    would break the complexity guarantees. We could write it down, in the specification of the Standard Library,
    but now it could stir a concern. Will it be evaluated?</p>
    
<p> We could make a general clause in the Standard Library that an implementation is allowed not to 
    put contract annotations on functions even if they are declared in the synopsis.</p>
 
<p> Alternatively, we could introduce a modification to the contract assertion syntax which says
    that these contract assertions even if declared are not runtime-evaluated. This is what 
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html"
           title="G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup, &ldquo;Support for contract based programming in C++&rdquo;"
           >[P0542R5]</a>
    calls an <code>audit</code> level. A special mode is required to trigger the evaluation of such predicates.
    </p> 
    
<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {})
  pre <strong>audit</strong>(is_strict_weak_order(first, last, comp, proj));  
</pre> 

<p> We cannot exhaustively test if a predicate is <em>equality-preserving</em>. We could call the predicate three times
    for each argument pair to see if it gives the same response all three times, 
    and if the values of the arguments didn't change much. However, we cannot use <code>operator==</code>,
    as it is never required by the concept constraints. We could say, "provided that <code>operator==</code> is available,
    perform additional tests". This could read like this:</p>

<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {})
  pre (maybe_is_equality_preserving(first, last, comp, proj)) 
    <strong>requires</strong> equality_comparable&lt;typename iterator_traits&lt;I&gt;value_type&gt;;  
</pre> 

<p> But this is still only a heuristic. Checking the result thrice does not mean
    that it <em>always</em> returns the same value for the same arguments.
    </p>


<h3>2.2 Checking range guarantees?</h3>


<p> The above predicates that we invented (<code>is_strict_weak_order</code>,
    <code>maybe_is_equality_preserving</code>) are still imperfect, as they have a precondition
    themselves: that [<code>first</code>, <code>last</code>) is a valid range.
    This cannot be checked with a C++ predicate. But it can be described formally.
    We can say that [<code>first</code>, <code>last</code>) is a valid range
    when the following algorithm finishes and doesn't have undefined behavior.</p>
 
 <pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S&gt;
void valid_range_axiom(I first, S last) 
{
  for (; first != last; ++first) {}
} 
</pre> 

<p> Declaring contract assertions with inexpressible predicates still has value.
    First, users and IDEs can read them. Second, they can be used as a basis for control flow
    analysis, symbolic analysis and value range analysis.</p>
    
<p> To support this type of a predicate, we would have to introduce a new kind of a declaration:
    either of a contract assertion or of a function:</p>

<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S&gt;
  <strong>axiom</strong> is_valid_range(I first, S last);   <em>// declared but never defined</em>
  
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {})
  pre <strong>axiom</strong>(is_valid_range(first, last));  <em>// modify the meaning of a precondition</em>
</pre> 

<p>Or alternatively:</p>

<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S&gt;
  <strong>axiom</strong> is_valid_range(I first, S last);   <em>// modify the meaning of a function declaration</em>
  
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {})
  pre (is_valid_range(first, last));  
</pre> 

<p> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html"
           title="G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup, &ldquo;Support for contract based programming in C++&rdquo;"
           >[P0542R5]</a>
    proposed <code>axiom</code>-level assertions. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2176r0.html"
           title="Andrzej Krzemieński, &ldquo;A different take on inexpressible conditions&rdquo;"
           >[P2176R0]</a> discusses the latter approach in more detail.      
  
  
<h3>2.3 Storing a postcondition state</h3>

<p> Finally, we would need to express the postcondition that the resulting sequence is a permutation of the initial sequence.
    In order to do that, we would have to observe both the initial and the result sequence at the same time.
    This means that we would have to store a copy of the input sequence and keep it until a postcondition is evaluated or an exception
    is thrown. We could introduce a lambda-capture-like syntax for making copies of the selected program state:</p>

<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(const I first, const S last, Comp comp = {}, Proj proj = {})
  post <strong>audit</strong> [in = vector(first, last)] (is_permutation(first, last, in.begin(), in.end()));  
</pre> 

<p> So, in order to express this postcondition, we would have to capture the sate of the entire range.
    Here we chose to store it in a <code>vector</code>. The choice is absolutely arbitrary. Note that while the algorithm
	<code>sort</code> is container-agnostic, now the postcondition ties the declaration of <code>sort</code> to a specific container.
	The predicate in the postcondition assertion expresses more than the plain language contract. While the latter 
	talks about the state of ranges before and after, the former now talks about creating a <code>vector</code>.
	</p>
<p> With creation of a vector, we no longer have a nice, pure predicate. It now can allocate memory, 
    perform an &Oscr;(<var>N</var>) copying and potentially throw.
    This postcondition is not only a "predicate". It is also an action executed when the function starts.
    It is difficult to imagine that this type of postcondition would be used for static analysis.
    We also need to mention that this check has complexity of &Oscr;(<var>N</var>&sup2;) , which is greater
    than the complexity of the sort.
    </p>


<h3>2.4 Putting all this together</h3>

<p> If we combine all the above assertions together, we would get:</p>


<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(const I first, const S last, Comp comp = {}, Proj proj = {})
  pre <strong>axiom</strong> (is_valid_range(first, last))
  pre <strong>audit</strong> (is_strict_weak_order(first, last, comp, proj))
  pre <strong>audit</strong> (maybe_is_equality_preserving(first, last, comp, proj)) 
    <strong>requires</strong> equality_comparable&lt;typename iterator_traits&lt;I&gt;value_type&gt;
  post (ranges::is_sorted(first, last, comp, proj))
  post <strong>audit</strong> [in = vector(first, last)] (is_permutation(first, last, in.begin(), in.end()));  
</pre> 

<p> That is admittedly a wall of text. Interestingly, only one of these assertions can be expressed with 
    what is proposed in 
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2900r7.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński, &ldquo;Contracts for C++&rdquo;">[P2900R7]</a>.
    </p>

<p> When adding contract assertions to the Standard Library components, one has to ask the question:
    what is the goal? There could be at least two answers:</p>
  
<ol>
<li>To give <em>every</em> possible hint to the tools to help them detect contract violations.</li>
<li>To document the parts of the interface that have not already been documented through types, concepts and 
    specifiers.</li>
</ol>  

<p> The above declaration satisfies the first goal. If we aim for the second goal, we could put fewer assertions.
    Concept <code>sortable</code> already implies the semantic properties of a strict weak order and 
    an equality-preserving function. So we could skip the corresponding assertions. Also the requirement that 
    [<code>first</code>, <code>last</code>) is a valid range is so obvious that we could think of skipping it.
    Also, a safer alternative is to use the range version of the algorithm, where we have a single object 
    that clearly represents a range. But if we only got rid of the contracts that represent the semantic requirements
    of contracts, we would end up with a slightly slimmer declaration.
    </p>
 
<pre>
template&lt;random_access_iterator I, sentinel_for&lt;I&gt; S, class Comp, class Proj&gt;
  requires sortable&lt;I, Comp, Proj&gt;
constexpr I ranges::sort(const I first, const S last, Comp comp = {}, Proj proj = {})
  pre <strong>axiom</strong> (is_valid_range(first, last))
  post (ranges::is_sorted(first, last, comp, proj))
  post <strong>audit</strong> [in = vector(first, last)] (is_permutation(first, last, in.begin(), in.end()));  
</pre>  
  
 
<h2>3. References</h2>


<ul>

  <li>[P0542R5] — G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup,
      "Support for contract based programming in C++" <br>
      (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html</a>).
      </li>
      <!--
        <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html"
           title="G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup, &ldquo;Support for contract based programming in C++&rdquo;"
           >[P0542R5]</a>
        -->
 
  <li>[P2176R0] — Andrzej Krzemieński,
      "A different take on inexpressible conditions" <br>
      (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2176r0.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2176r0.html</a>).
      </li>
      <!--
        <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2176r0.html"
           title="Andrzej Krzemieński, &ldquo;A different take on inexpressible conditions&rdquo;"
           >[P2176R0]</a>
        -->
        
<li>[P2345R0] &mdash; Sean Parent,
    "Relaxing Requirements of Moved-From Objects", <br>
    (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2345r0.pdf">"https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2345r0.pdf"</a>).
    </li>
    <!--
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2345r0.pdf"
       title="Sean Parent, &ldquo;Relaxing Requirements of Moved-From Objects&rdquo;">[P2345R0]</a>
    -->
    
<li>[P2900R7] &mdash; Joshua Berne, Timur Doumler, Andrzej Krzemieński,
    "Contracts for C++", <br>
    (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2900r7.pdf">"https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2900r7.pdf"</a>).
    </li>
    <!--
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2900r7.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński, &ldquo;Contracts for C++&rdquo;">[P2900R7]</a>
    -->

    
</ul>



</body></html>
