<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<style type="text/css">
pre {margin-left:20pt; font-family: "Consolas", "Lucida Console", monospace;  }
code {font-family: "Consolas", "Lucida Console", monospace; }
pre > i   {  font-style:italic; }
code > i  {  font-style:italic; }
pre > em  {  font-style:italic; }
code > em {  font-style:italic; }
body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example   { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { 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; }

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.5empadding-right: 0.5em; ; }
blockquote.stdins { text-decoration: underline;  color: #000000; background-color: #C8FFC8;  border: 1px solid #B3EBB3; padding: 0.5em; }
table.header { border: 0px; border-spacing: 0;  margin-left: 0px; font-style: normal; }
table { border: 1px solid black; border-spacing: 0px;  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;  padding-left: 0.4em; border: none;  padding-right: 0.4em; border: none; }
td { text-align: left; vertical-align: top;  padding-left: 0.4em; border: none;  padding-right: 0.4em; border: none; }
</style>

<title>A different take on inexpressible conditions</title>
</head>

<body>

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;</th><th> </th><td>P2176r0</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;</th><th> </th><td>2020-05-27</td>
  </tr>
  <tr>
    <th>Audience:&nbsp;&nbsp;</th><th> </th><td>SG21</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;</th><th> </th><td><address>Andrzej Krzemie&#324;ski &lt;akrzemi1 (@) gmail (.) com&gt;</address></td>
  </tr>
</tbody></table>

<h1><a name="title">A different take on inexpressible conditions</a></h1>


<p> This paper proposes a solution for handling predicates in preconditions
    and postconditions that cannot be expressed using C++ syntax, such as
    "being reachable" for iterators, in a different way than what we have seen in
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/P0542r5.html">[P0542r5]</a>.
    Rather than annotating preconditions and postconditions as inexpressible,
    we propose to annotate the functions used inside as inexpressible.
    </p>

<table>
  <tr><th>P0542r5</th><th>This proposal</th></tr>
  <tr><td>

<pre>bool is_null_terminated(const char *); <em>// never defined</em>

void use_str(const char* s)
  [[pre: s != nullptr]]
  [[pre <strong>axiom</strong>: is_null_terminated(s)]];

void use_opt_str(const char* s)
  [[pre <strong>axiom</strong>: s == nullptr || is_null_terminated(s)]];</pre>

  </td><td>

<pre><strong>axiom</strong> is_null_terminated(const char *); <em>// no definition expected</em>

void use_str(const char* s)
  [[pre: s != nullptr]]
  [[pre: is_null_terminated(s)]];

void use_opt_str(const char* s)
  [[pre: s == nullptr || is_null_terminated(s)]];</pre>

  </td></tr>
  <caption>Tony table</caption>
</table>


<h2><a name="motivation">1. Motivation</a></h2>

<p>There are predicates common in C++ that are defined formally in human language, but cannot be expressed
as a C++ function, such as that an object of type <code>const char*</code> represents a C-style string, i.e.,
</p>

<ol>
<li>It is not null (this part is expressible).</li>
<li>The array under the pointer is null-terminated.</li>
</ol>

<p>
While there is no way to check this condition at runtime, expressing it using a function signature,
like <code>is_null_terminated(str)</code> is still beneficial as static analyzers can make use of it by treating
it as a symbol, and comparing if one function that requires an argument annotated with this symbol
consumes the value produced by another function that also annotates its return value with the same symbol.
Consider:
</p>


<pre>const char* make_name()
  [[post str: str != nullptr &amp;&amp; is_null_terminated(str)]]
  ;

size_t strlen(const char* str)
  [[pre: str != nullptr &amp;&amp; is_null_terminated(str)]]
  ;

size_t l = strlen(make_name());
</pre>

<p> Condition <code>str != nullptr</code>, which is part of the precondition of function
    <code>strlen()</code>, can be runtime-checked to assert (partial) program correctness.
    Regarding the second part, static analyzer can compare symbols:
    <code>is_null_terminated</code> appears as postcondition of <code>make_name()</code>
    and also as a precondition in <code>strlen()</code>, so assuming that <code>make_name()</code>
    fulfills its contract (this assumption may be verified when compiling <code>make_name()</code>),
    the analysis can conclude that <code>is_null_terminated(str)</code> will be satisfied in the
    precondition of <code>strlen</code>.
    Thus, function signature <code>is_null_terminated(const char*)</code> can help in determining
    program correctness, even if we cannot provide its body.
    </p>

<p> Note that a static analyzer can perform a similar analysis for the part <code>str != nullptr</code>
    of the precondition, however as such static analysis is very resource consuming, it is a reasonable
    strategy to perform it only for predicates of which we know that they cannot be runtime checked.
    So the semantics of a function signature indicated as inexpressible is, "perform symbolic static
    analysis for this condition, rather than trying to inject runtime defensive checks." This important
    use case covered in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/P0542r5.html">[P0542r5]</a>
    was ignored in proposals like
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1429r3.pdf">[P1429r3]</a>, whch
    allowed specifying one of four "behaviors" for each contract declaration, but provided no way of
    saying, whether a given declaration should be selected for symbolic analysis or not.
    </p>


<h2><a name="previous">2. Inexpressibility as contract statement "level"</a></h2>


<p> The solution to this problem in
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/P0542r5.html">[P0542r5]</a>
    was to annotate the precondition or postcondition as special: designated to be treated as
    symbol and subject to static analysis. Because such annotation appertains to the entire predicate,
    if some part of a predicate can be runtime-checked and the other cannot, the predicate needs to
    be split across two declarations:
    </p>

<pre>const char* make_name()
  [[post str: str != nullptr]]
  [[post <strong>axiom</strong> str: is_null_terminated(str)]]
  ;

size_t strlen(const char* str)
  [[pre: str != nullptr]]
  [[pre <strong>axiom</strong>: is_null_terminated(str)]]
  ;
</pre>

<p> Word <code>axiom</code> is used to indicate that this precondition needs to be verified by
    the static analyzer rather than runtime-checked. (At least, this was <em>one of</em> the
    original motivations. Other potential use cases mentioned were to annotate run-time 
    checkable functions but with lethal side effects.)
    </p>

<p> This solution had some issues. First, it conflated the notion of "contract level" (which
    says about the relative runtime cost of evaluating the function body versus evaluating the
    predicate) with the property of requiring and not requiring the function to be ORD-used
    (i.e., requiring that the function should have a definition). Thus, changing the contract 
    declaration level (form <code>axiom</code> to any other) can change a well formed program
    into an ill-formed one.
    </p>

<p> Second, it sometimes requires a precondition that is composed of expressible and inexpressible
    parts to be separated into two annotations. If the two parts are connected by a logical
    conjunction (operator <code>&amp;&amp;</code>) this is easily doable, as in the above example. However,
    if operator <code>||</code> is used, as in:

<pre>size_t consume_optional_name(const char* name)
  [[pre: name == nullptr || is_null_terminated(name)]]
  ;
</pre>

<p> a separation is not possible, and the part that is easily runtime-checked must now be performed
    by the static analyzer, wasting its precious resources.
    </p>



<h2><a name="this_proposal">3. Inexpressibility as function property</a></h2>


<p> The alternative that we propose is that it is the functions used in predicates
    that should be indicated as subject to static analysis, rather than preconditions
    and postconditions. This is similar to "properties" described in
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf">[N3351]</a>.
    In this proposal the examples above would be written as:
    </p>

<pre><strong>axiom</strong> is_null_terminated(const char* str);

const char* make_name()
  [[post str: str != nullptr &amp;&amp; is_null_terminated(str)]]
  ;

size_t strlen(const char* str)
  [[pre: str != nullptr &amp;&amp; is_null_terminated(str)]]
  ;

size_t consume_optional_name(const char* name)
  [[pre: name == nullptr || is_null_terminated(name)]]
  ;
</pre>

<p> Keyword <code>axiom</code> indicates that to a certain extent <code>is_null_terminated</code>
    can be treated as function returning <code>bool</code>, and that its body cannot be expressed
    as a C++ predicate. Whenever it appears in a precondition or a postcondition, it is
    encouragement for the static analyzer to perform a symbolic analysis on it.
    </p>

<p> This establishes a well defined semantics of keyword <code>axiom</code>: it indicates a
    predicate that is meant to be consumed by the static analyzer.
    </p>

<p> An inexpressible predicate defined this way behaves like a function declaration in some
    aspects: it can be a template, it can be overloaded (also by a regular function), it can be
    looked up during overload resolution.
    </p>

<p> But it also differs from normal functions. First, it can only be used inside a contract
    declaration. (Later we will see a second place where it could also be useful.)
    </p>

<p> Second, because it cannot be run-time evaluated, and because contract declarations can be
    used to generate run-time code, special rules apply. In a run-time check, the subexpression that
    is marked as inexpressible is skipped: treated as if it returned <code>true</code>. This is intuitive
    when the entire contract predicate is inexpressible, or when the inexpressible predicate is an
    operand of logical conjunction:</p>

<pre>void fun1(const char* str)
  [[pre: str != nullptr &amp;&amp; is_null_terminated(str)]];

void fun2(const char* str)
  [[pre: str != nullptr]]
  [[pre: is_null_terminated(str)]];

void test(const char* str)
{
  fun1(str);
  fun2(str);
}

<em>// test() under certain build "mode" can render code equivalent to:</em>

void test(const char* str)
{
  SYMBOLIC_CHECK(is_null_terminated(str));
  { if (!(str != nullptr)) contract_violation_handler(); }
  fun1(str);

  SYMBOLIC_CHECK(is_null_terminated(str));
  { if (!(str != nullptr)) contract_violation_handler(); }
  fun2(str);
}</pre>

<p> However, if an inexpressible condition is an operand of logical disjunction
    things get complicated. The expression cannot be treated as if it returned
    <code>true</code> as it would incorrectly cause an expression always to succeed.
    In order to prevent that, we allow the inexpressible predicate only to appear on
    the right-hand side of an </em>or-expression</em> when the other operand is expressible:
    </p>

<pre>void opt_fun1(const char* str)
  [[pre: is_null_terminated(str) || str == nullptr]]; <em>// compiler error</em>

void opt_fun2(const char* str)
  [[pre: str == nullptr || is_null_terminated(str)]];

void test(const char* str)
{
  opt_fun2(str);
}

<em>// test() under certain build "mode" can render code equivalent to:</em>

void test(const char* str)
{
  { if (!(str == nullptr)) SYMBOLIC_CHECK(is_null_terminated(str)); }
  opt_fun2(str);
}</pre>

<p> This follows a similar approach as was taken for <code>requires</code>-clauses:
    logical expressions involving inexpressible predicate operands try to look
    like normal expressions, but they are subject to special rules. For a similar reason,
    you cannot negate an inexpressible predicate: requiring it would always be a
    logic error. You may want to know if <code>i</code> is reachable from <code>j</code>
    in a contract statement, but you never need to know if <code>i</code> is
    <em>unreachable</em> from <code>j</code>. You may want to know if a string is
    null-terminated, but you never want to know if it is null-not-terminated. You may want
    to know if a pointer points to valid memory, but never do you need to know if a pointer points
    to invalid memory.</p>

<p> You can combine expressible and inexpressible operands in one logical expression,
    but they have to be partitioned: first expressible, followed by inexpressible operands.
    </p>


<p> One way of looking at it is that we provide a limited form of
    a three-state algebra but encoded in type <code>bool</code>.
    </p>

<p> The benefit of declaring predicates as inexpressible (rather than conflating
    them with contract statement levels) allows the levels to be uniform: they only say
    when we want to evaluate them and nothing else: we do not say if the definition of a predicate may or may not be available. Even if we choose to perform "literal semantics" (like in
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1429r3.pdf">[P1429r3]</a>),
    the model becomes simpler: any semantic can be assigned to any contract declaration
    (rather than saying that for some pre-/postconditions you can only assign "ignore" semantics).
    </p>

<p> As a consequence of this, generating runtime-checks from contract annotations depends
    not only on "levels" or "literal semantics", but also on whether the predicates or
    parts thereof are marked as inexpressible.
    </p>

<h3><a name="this_proposal.overloading">3.1. Overloading</a></h3>


<p> The fact that inexpressible predicates can be overloaded allows providing
    more specialized predicate overloads for which the definition can be expressed in C++.
    Consider predicate expressing the reachability of iterators:</p>

<pre>template &lt;input_iterator It, sentinel_for&lt;It&gt; S&gt;
  <strong>axiom</strong> is_reachable(It begin, S end);
</pre>

<p>In case we have a special debugging-purpose iterator, it may have enough redundant information to tell if it is reachable from another iterator (like pointer to the underlying container and an index in that container). In that case we can provide an overload that is cheap to evaluate at runtime, and we will <em>not</em> mark it as inexpressible:</p>

<pre>template &lt;typename T&gt;
bool is_reachable(vector_debug_iterator&lt;T&gt; begin, vector_debug_iterator&lt;T&gt; end)
{
  return end.is_reachable_from(begin);
}</pre>


<p> Now, a function that uses the requirement <code>is_reachable()</code>
    does not need to know about all these overloads. It just uses the name:
    </p>

<pre>template &lt;input_iterator It, sentinel_for&lt;It&gt; S, invokable&lt;value_type&lt;It&gt;&gt; F&gt;
void for_each(It begin, S end, F f)
  [[pre: is_reachable(begin, end)]];
</pre>

<p> While <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/P0542r5.html">[P0542r5]</a>
    also allowed to express this, it required providing an overload of an algorithm, possibly in
    somebody else's namespace:</p>

<pre><em>// in P0542r5:</em>

template &lt;input_iterator It, sentinel_for&lt;It&gt; S&gt;
bool is_reachable(It begin, S end); <em>// never defined</em>

template &lt;input_iterator It, sentinel_for&lt;It&gt; S, invokable&lt;value_type&lt;It&gt;&gt; F&gt;
void for_each(It begin, S end, F f)
  [[pre <strong>axiom</strong>: is_reachable(begin, end)]];

template &lt;typename T&gt;
bool is_reachable(vector_debug_iterator&lt;T&gt; begin, vector_debug_iterator&lt;T&gt; end)
{
  return end.is_reachable_from(begin);
}

template &lt;typename T, invokable&lt;value_type&lt;vector_debug_iterator&lt;T&gt;&gt;&gt; F&gt;
void for_each(vector_debug_iterator&lt;T&gt; begin, vector_debug_iterator&lt;T&gt; end, F f)
  [[pre: is_reachable(begin, end)]];
</pre>



<h2><a name="syntax">4. Syntax considerations</a></h2>


<p> It is possible to provide the same functionality with less intrusive language changes:
    </p>

<pre>bool is_null_terminated(const char* str) = <strong>axiom</strong>;</pre>

<p> With this notation <code>axiom</code> can be made a context-sensitive keyword.</p>

<p> However, putting it at <em>decl-specfier</em> position has certain benefits.
    First, it makes it clear that we are defining a different entity than a function:
    an inexpressible predicate. It cannot be put in some places where a
    <code>bool</code>-returning function can appear. Second, it reflects clearer that
    the return type is <code>bool</code> type-system wise, but the value computation in
    logical expressions is different. It is only this special type that an inexpressible
    predicate can have, so there is no point in adding the extra flexibility for the
    user to specify any return type only to later inform him/her that it will not compile.
    </p>

<p> This also clearly indicates that we are sort-of implementing a three-state algebra
    in type <code>bool</code>.
    </p>

<p> Finally, by clearly stating that an inexpressible predicate is a distinct entity,
    we allow room for potential further extensions. While we do not propose these
    extensions now, this section indicates the future possible evolution directions.
    </p>

<h3><a name="syntax.partial_body">4.1 Partial implementations</a></h3>

<p> For instance, when in some special cases the value of a generally
    inexpressible predicate can be determined at run-time, we can allow
    the programmer to specify this. Consider the
    specialization of <code>is_reachable()</code> for contiguous iterators. When
    <code>std::less&lt;&gt;{}(p, q) == false</code> we know for sure that
    <code>p</code> is not reachable from <code>q</code>. In case
    <code>std::less&lt;&gt;{}(p, q) == true</code> we do not know the answer.
    But this partial information is better than no information, so we could
    express it as:
    </p>

<pre>template &lt;std::contiguous_iterator IT&gt;
<strong>axiom</strong> is_reachable(IT begin, IT end)
  = !std::less&lt;&gt;{}(to_address(end), to_address(begin)) &amp;&amp; std::indeterminate();
</pre>

<p>where <code>std::indeterminate()</code> is defined as:</p>

<pre><strong>axiom</strong> indeterminate();</pre>

<p> This is the second context where we would allow the invocation of an
    inexpressible predicate. Owing to short-circuiting <code>is_reachable</code>
    defined like this could for some inputs provide a runtime result
    <code>false</code>. Similarly, we can define a value constraint
    on a C-style string:
    </p>

<pre><strong>axiom</strong> is_c_str(const char * s)
  = (s != nullptr) &amp;&amp; std::indeterminate();
</pre>

<p> A logical disjunction in the definition of an inexpressible predicate
    is also possible and could return <code>true</code> for some inputs:
    </p>

<pre><strong>axiom</strong> is_optional_c_str(const char * s)
  = (s == nullptr) || std::indeterminate();
</pre>

<p> The same special rules apply in this context: inexpressible predicates
    can be mixed with normal predicates, but normal predicates must come
    first. Similarly, you cannot negate an inexpressible predicate.
    </p>

<h3><a name="syntax.minimum_usage">4.3 Demonstration of usage</a></h3>

<p> Another possible extension is to use the body of an inexpressible predicate
    <code>P</code> to describe a minimum program that relies on <code>P</code>.
    Consider:
    <p>

<pre><strong>axiom</strong> is_null_terminated(const char* str)
  [[pre: str != nullptr]]
{
  while (*str != '\0') ++str;
}
</pre>

<p> This would mean that the code in braces if it were to be evaluated is
    required to:</p>

<ol><li>have no UB or other contract violation,</li>
    <li>finish (not run forever).</li>
    </ol>

<p>Similar examples:</p>

<pre>template &lt;input_iterator It, sentinel_for&lt;It&gt; S&gt;
<strong>axiom</strong> is_reachable(It begin, S end)
{
  while(begin != end) ++begin;
}

<strong>axiom</strong> points_to_valid_memory(auto* p)
  [[pre: p != nullptr]]
{
  *p;
}

<strong>axiom</strong> is_deletable(auto* p)
  [[pre: p != nullptr]]
{
  delete p;
}</pre>

<p> The code inside the body has no effect on the run-time code:
    it is only meant to be a feedback for static analysis.
    Inexpressible predicates have the same constraints as functions
    declared with <code>inline</code>. A program is ill-formed NDR if two TUs
    see different definitions of this function.</p>

<p> These additional features do not necessarily have to be added to the
    language along with inexpressible predicates. But they illustrate how
    inexpressible predicates have room to evolve in the future.
    </p>

<p> Name "axiom" is short and attractive, so it may not be suitable for a
    reserved keyword. So a different name might be required:
    <code>co_axiom</code>, <code>inexpressible</code>.
    </p>


<h2><a name="unimplemented">5. Not-yet-implemented predicates</a></h3>

<p> This solution partially covers the use case where I have only provided
    a declaration for my predicate but don't have a precondition definition
    yet. If the only useage of the not-yet-implemented
    predicate is in preconditions and postconditions, then I can declare it
    temporarily as an inexpressible predicate. Later, when I provide an
    implementation, I can change it to a normal function.
    </p>

<p> This will not work, though, if I have to negate my predicate, 
    due to the special semantics of inexpressible predicates.
    </p>


<h2><a name="out_of_scope">6. Problems not addressed</a></h2>


<p> This proposal does not address the following problems that might
    require assisting the static analyzer.</p>

<h3><a name="out_of_scope.equiv">6.1. Relations between inexpressible predicates</a></h3>

<p> It is possible that that two libraries declare two inexpressible predicates
    that describe the very same condition, like <code>library1::is_null_terminated</code>
    and <code>Lib2::isNullTerminated</code>. A static analyzer might need a hint indicating
    that the two conditions are equivalent. Similarly, there might be a need
    to hint the static analyzer that one predicate implies another. For instance,
    <code>is_sorted</code> implies <code>is_partially_sorted</code>. This is similar to
    functionality described in
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2887.pdf">[N2887]</a>.
    This is a possible future extension, but we do not propose it at this time,
    as this information can be fed to static analyzers by other means than C++ source code,
    through analyzer-specific configuration files.
    </p>


<h3><a name="out_of_scope.side_effects">6.2. Side effects in predicates</a></h3>

<p> Another often quoted feature is the ability to allow expressions with
    side effects in contract predicates and provide a guarantee that they are never
    evaluated. For instance a requirement that a range has size equal to 1
    could be expressed as:</p>

<pre>template &lt;input_iterator It, sentinel_for&lt;It&gt; S, invokable&lt;value_type&lt;It&gt;&gt; F&gt;
void for_one(It begin, S end, F f)
  [[pre: ++begin == end]];
</pre>

<p> Again, this is a possible future extension, however, we do not see
    a compelling reason to provide this. <code>input_iterator</code>s
    have been mentioned as a use case; but we can think of no single precondition
    or postcondition in STL that would benefit from such capability.
    algorithms constrained on <code>input_iterator</code>s usually
    just traverse the range, and the only requirement for this to work is
    <code>is_reachable</code>, which has to be declared inexpressible
    anyway.
    </p>


<h3><a name="out_of_scope.expensive_pred">6.3. Very, very, very, expensive predicates</a></h3>


<p> Some predicates can be implemented, sometimes quite easily, but are so computationally
    that we would never want them to be evaluated, even in <code>audit</code> builds.
    For instance, comparing if two regular expressions are equivalent is a PSPACE-complete problem.
    </p>
    
<p> This proposal does not address this problem directly, but gives a workaround. Even if you
    can provide a body for your predicate, also provide the inexpressible version thereof:
    </p>

<pre>bool equivalent(regexp const&amp; r, regexp const&amp; s) { <em>/* implementation */</em>; }

<strong>axiom</strong> symbollically_equivalent(regexp const&amp; r, regexp const&amp; s);</pre>

<p> And use the latter definition to employ the static analyzer for correctness checking based on
    symbols.
    </p>

<p> This does not, however, handle the situation where a predicate is toooo expensive only
    in certain contexts. For instance,   equality of hash-maps has quadratic complexity, which can be
    evaluated as predicates in some functions that are known to take small maps. But in other functions,
    we know we never want to evaluate them even in <code>audit</code> builds. In these cases being 
    "too expensive" is a property of a particular contract statement rather than of a predicate.
    </p>
    
<p> Such use case, if we find it worth addressing, could be handled by additional build level
    <code>never</code>, but it still seems worthwile to keep the two things separate: an inexpressible
    predicate and "never evaluate this precondition here".
    </p>



<h2><a name="acknowledge">7. Acknowledgments</a></h2>


<p> Gor Nishanov has reviewed this proposal and offered a valuable feedback.
    Andrew Sutton and Joshua Berne, Tomasz Kami&#324;ski and John Lakos offered a number of improvements to this paper.
    Marcin Grzebieluch suggested covering the relationships between predicates.
    </p>



<h2><a name="literature">8. References</a></h2>


<ol>

  <li>B. Stroustrup, A. Sutton, et al.,
      "A Concept Design for the STL",
      (N3351, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf</a>).
      </li>

  <li>Gabriel Dos Reis, Bjarne Stroustrup, Alisdair Meredith,
      "Axioms: Semantics Aspects of C++ Concepts",
	  (N2887, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2887.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2887.pdf</a>).
	  </li>

  <li>Lisa Lippincott,
      "Procedural function interfaces",
	  (P0465r0, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0465r0.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0465r0.pdf</a>).
	  </li>

  <li>G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup,
      "Support for contract based programming in C++",
      (P0542r5, <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>

  <li>Joshua Berne, John Lakos,
      "Contracts That Work",
	  (P1429r3, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1429r3.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1429r3.pdf</a>).
	  </li>

</ol>

</body></html>
