﻿<html><head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Defaulted comparison operators</title>
<style type="text/css">
.addition {
    background-color: #66FF99;
}
.removal {
    text-decoration: line-through;
}
li {
    padding-bottom: 0.3em;
}
pre {
    background-color: #F7F6dc;
    margin-left: 3em;
    margin-right: 3em;
    padding: 1em 1em 1em 1em;
    font-size: 90%;
}
</style>
</head>

<body>

  <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="619">
    <tr>
      <td width="167" align="left" valign="top">Document number:</td>
      <td width="452"><i>N3950</i></td>
    </tr>
    <tr>
      <td width="167" align="left" valign="top">Date:</td>
      <td width="452"><i>2014-02-19</i></td>
    </tr>
    <tr>
      <td width="167" align="left" valign="top">Project:</td>
      <td width="452">Programming Language C++, Language Evolution Working Group</td>
    </tr>
    <tr>
      <td width="167" align="left" valign="top">Reply-to:</td>
      <td width="452">Oleg Smolsky <a href="mailto:oleg.smolsky@gmail.com">oleg.smolsky@gmail.com</a></td>
    </tr>
  </table>

    <h1>Defaulted comparison operators</h1>

    <h2>I. Introduction</h2>
    <p>Provide means of generating default equality, inequality and comparison member operators
        for user-defined types. This is strictly
       an "opt in" feature so that semantics of existing code remain intact.

    <h2>II. Motivation and scope</h2>

    <p>This feature would be useful for modern C++ code that operates with types
       composed of "regular" members. The definition of equality is trivial in such cases -
       member-wise comparison. Inequality can then be generated as an inverse.
    <p>This proposal is based on the notion of "regular" types that naturally compose. Such
       cases are becoming more prevalent as people program more with value types and writing
       (in)equality manually becomes tiresome. This is especially true when trying to
       lexicographically compare members.

    <p>Consider the following trivial example where a C++ type represents some kind of a user
        record:

        <pre>
struct user {
    uint32_t id, rank, position;

    std::string first_name, last_name;

    std::string address1, address2, city, state, country;
    uint32_t us_zip_code;

    bool operator==(const user &amp;) const;
    bool operator!=(const user &amp;) const;

    bool operator&lt;(const user &amp;) const;
    bool operator&gt;=(const user &amp;) const;
};</pre>

        <h3>Verbosity</h3>
        The structure consists of regular members and the implementation of the equality operator 
        is trivial yet verbose:

        <pre>
bool user::operator==(const user &amp;r) const {
    return id == r.id &amp;&amp;
           rank == r.rank &amp;&amp;
           position = r.position &amp;&amp;
           address1 == r.address1 &amp;&amp;
           address2 == r.address2 &amp;&amp;
           city == r.city &amp;&amp;
           state == r.state &amp;&amp;
           country == r.country &amp;&amp;
           us_zip_code == r.us_zip_code;
}

bool user::operator&lt;(const user &amp;r) const {
    // Can implement a full lexicographical comparison of members, but can 
    // also cheat by using standard libraries
    return std::tie(id, rank, position,
                    address1, address2, city, state, country, 
                    us_zip_code)
           &lt;
           std::tie(r.id, r.rank, r.position, 
                    r.address1, r.address2, r.city, r.state, r.country,
                    r.us_zip_code);
}</pre>

        Specifically, this code, while technically required, suffers from the following issues:
        <ul>
        <li>needlessly verbose - every member is already equality comparable
        <li>error prone - the author could miss a member, or the implementation may become stale 
            when a new member is added
        <li>not in the spirit of Modern C++: correct things should be intuitive and easy
        </ul>

        <h3>Correctness</h3>

        <p>It is vital that equal/unequal, less/more-or-equals and more/less-or-equal pairs
        behave as boolean negations of each other. After all, the world would make no sense
        if both <code>operator==()</code> and <code>operator!=()</code> returned <i>false</i>!
        As such, it is common to implement these operators in terms of each other:

        <pre>
bool user::operator!=(const user &amp;r) const {
    return !(*this == r);
}

bool user::operator!=(const user &amp;r) const {
    return !(*this == r);
}

bool user::operator&gt;=(const user &amp;r) const {
    return !(*this &lt; r);
}
bool user::operator&gt;(const user &amp;r) const {
    return r &lt; *this;
}
bool user::operator&lt;=(const user &amp;r) const {
    return !(*this &gt; r);
}
        </pre>

        Specifically:
        <ul>
        <li>Based on my experience, this template is applicable to the vast
            majority of types that define comparison operators
        <li>The users should have "short hand" for stating what is common, correct and simple
        <li>These relations are algebraic in nature and must be considered carefully. For example,
            <code>operator&lt;()</code> must remain transitive in its nature.
        </ul>



    <h2>III. Design decisions</h2>
    <h3>The proposed syntax</h3>
        <p>Member-wise generation of special functions is already present in the Standard 
        (see Section 12), so it seems natural to extend the scope of generation and reuse
        the existing syntax.

        <p>The proposed syntax for generating the new "explicitly defaulted" member functions
           is as follows:
    <pre class="code">
struct Thing {
    int a, b, c;
    std::string d;

    bool operator==(const Thing &amp;) const = default;
    bool operator&lt;(const Thing &amp;) const = default;

    bool operator!=(const Thing &amp;) const = default; 

    bool operator&gt;=(const Thing &amp;) const = default; 
    bool operator&gt;(const Thing &amp;) const = default; 
    bool operator&lt;=(const Thing &amp;) const = default;
};</pre>
    
    <p>I feel this is a natural choice because:
       <ul>
            <li>C++11 already has member function specifiers such as "default" and "delete"
            <li>Users can "opt in" to get the new behavior
            <li>Member functions are explicitly declared and are, hence, visible in the source
                code. This is generally helpful when humans read the code.
       </ul>

    <h3>Other points of consideration</h3>
    <p>It is possible to mandate that every explicitly defaulted operator is to be implemented
       in a member-wise fashion. In fact, it would we consistent with copy construction,
        assignment and equality. However:
        <ul>
            <li>Such an implementation is not useful. It would generate uselss code which
                may be sizeable due to the number of members.
            <li>The most logical choice for inequality is the boolean inverse of equality. The
                same applies to the other operators - they can all be derived.
            <li>Users are still free to implement the operators in any way the see fit
        </ul>

    <h2>IV. Implementation</h2>
        <p>I have a working prototype implementation using Clang that does the following:
        <ul>
            <li>parses the proposed syntax
            <li>declares and defines the new member functions for an arbitrary number of built-in and   
                composite members
            <li>Equality is generated in a member-wise fashion. Both built-in and user-defined types 
                are supported.
            <li><code>operator&lt;()</code> is implemented via a call to <code>std::tie()</code>
        </ul>

        <p> The following additional work is needed to get closer to production quality:
        <ul>
            <li>add support for base classes
            <li>enhance diagnostics pertinent to non-regular members
            <li>test against a large body of code
        </ul>

    <h2>V. Technical specifications</h2>
    <h3>Correction for 8.4.2 "Explicitly-defaulted functions [dcl.fct.def.default]" </h3>

    <ol>
    <li>A function definition of the form:<br>
        <i>attribute-specifier-seq<sub>opt</sub> decl-specifier-seq<sub>opt</sub> declarator virt-specifier-seq<sub>opt</sub></i> = <b>default</b> ;<br>
        is called an explicitly-defaulted definition. A function that is explicitly defaulted shall<br>
        — be a special member function, or <span class="addition">an explicitly defaultable operator
       member function. See [defaultable]</span>
    </ol>

    <h3>New section in 8.4</h3>

    <b>8.4.4 Explicitly defaultable operator member functions [defaultable]</b>
    <p>The following operator member functions can be explicitly defaulted:
        <ol>
        <li>Equality operators: <code>operator==()</code> and <code>operator!=()</code> [class.equality]
        <li>Comparison operators: <code>operator&lt;()</code>, <code>operator&gt;()</code>,
            <code>operator&lt;=()</code> and <code>operator&gt;=()</code> [class.comparison]
        </ol>

    <h3>Correction for "12 Special member function [special]" </h3>
    <p>The default constructor (12.1), copy constructor and copy assignment operator (12.8), 
        move constructor and move assignment operator (12.8) and destructor (12.4) are special
        member functions. 
        <span class="addition">These, together with equality operators (12.10) and
        comparison operators (12.11) can be explicitly defaulted as per 
        [dcl.fct.def.default]</span>

    <h3>New section in 12</h3>
    <p><b>12.10 Equality operators [class.equality]</b>
    <ol>
        <li>A non-union class can provide overloaded equality and inequality operators as per 
            [over.oper]. A default implementation can be generated via the
            <code>= default</code> notation as these member functions can be explicitly
            defalted as per [dcl.fct.def.default].

        <li>The defaulted <code>operator==()</code> is generated if and only if all 
            sub-objects and base classes are intergal types or provide <code>operator==()</code>

            <br><br>

            <small><i>Alternative: IFF they all satisfy the requirements of the <i>EqualityComparable</i>
            concept (17.6.3.1).</i></small>

        <li>The implicitly-defined equality operator for a non-union class X performs 
            memberwise equality comparison of its subobjects. Direct base classes of X
            are compared first, in the order of their declaration in the base-specifier-list,
            and then the immediate non-static data members of X are compared, in
            the order in which they were declared in the class definition.<br>

            Let x be either the parameter of the function or, for the move operator, an xvalue 
            referring to the parameter. Each subobject is compared in the manner appropriate to its type:

            <ul>
                <li>if the subobject is of class type, as if by a call to <code>operator==()</code> with
                    the subobject as the object expression and the corresponding subobject of x as a
                    single function argument (as if by explicit qualification; that is, ignoring any 
                    possible virtual overriding functions in more derived classes);

                <li>if the subobject is an array, each element is compared, in the manner appropriate 
                    to the element type;

                <li>if the subobject is of trivial type, the built-in "equality" operator is used.
            </ul>

        <li>The implicitly-defined inequality operator for a non-union class X performs a call
            to <code>operator==()</code> and returns a boolean negation of the result
    </ol>

    <p><b>12.11 Comparison operators [class.comparison]</b>
    <ol>
        <li>A non-union class can provide overloaded comparison operators as per [over.oper]. 
            A a default implementation via the
            <code>= default</code> notation as these member functions can be explicitly defaulted
            as per [dcl.fct.def.default].

        <li>The defaulted <code>operator&lt;()</code> is generated if and only if all 
            sub-objects and base classes are integral types or provide <code>operator&lt;()</code>

            <br><br>
            <small><i>Alternative: IFF they all satisfy the requirements of the <i>LessThanComparable</i> 
            concept (17.6.3.1).</i></small>

        <li>The implicitly-defined <code>operator&lt;()</code> for a non-union class X performs
            lexicographical comparison of member values in a manner compatible to
            <code>std::tie()</code>.
            Direct base classes of X are compared first, in the order of their declaration in the 
            base-specifier-list, and then the immediate non-static data members of X are compared,
            in the order in which they were declared in the class definition.<br>

            Let x be either the parameter of the function or, for the move operator, an xvalue 
            referring to the parameter. Each subobject is compared in the manner appropriate to its type:

            <ul>
                <li>if the subobject is of class type, as if by a call to <code>operator&lt;()</code> with
                    the subobject as the object expression and the corresponding subobject of x as a
                    single function argument (as if by explicit qualification; that is, ignoring any 
                    possible virtual overriding functions in more derived classes);

                <li>if the subobject is an array, each element is compared, in the manner appropriate 
                    to the element type;

                <li>if the subobject is of trivial type, the built-in "less than" operator is used.
            </ul>
        <li>The implicitly-defined <code>operator&gt;=()</code> for a non-union class X performs a call
            to <code>operator&lt;()</code> and returns a boolean negation of the result

        <li>The implicitly-defined <code>operator&gt;()</code> for a non-union class X performs a call
            to <code>operator&lt;()</code> but reverses the arguments

        <li>The implicitly-defined <code>operator&lt;=()</code> for a non-union class X performs a call
            to <code>operator&gt;()</code> and returns a boolean negation of the result

    </ol>

    <h2>VI. Related ideas and discussion</h2>
        The following related ideas need consideration for the future:
        <ol>
        <li>It is possible to generate definitions in terms of the operators being used, 
            instead of the "key" operator? Would it make sense? Such specification introduces 
            even more variance into the generated code.

        <li>Is it possible to generate these <code>operator==()</code> implicitly? How do we 
            deal with previously defined non-member operators? (Perhaps we can allow non-member 
            operators to hide implicitly generated member ones?).

        <li>Is it useful to support non-member comparison functions? This is not technically
            hard, but introduces additional (somewhat unusual) syntax.

        <li>The current specification states that <code>operator&lt;()</code> performs 
            member comparisons in a manner compatible to <code>std::tie()</code>. Such a 
            statement is easy to write and prototype, but, if taken literarily, puts an
            unusual dependency between the core language and the standard library. It may be
            better to spell out what a "lexicographical comparison" is.
        </ol>
    <h2>VII. Acknowledgments</h2>
        <p>The fundamental idea comes from Alex Stepanov as his work revolves around 
        "regular" types. Such types should be automatically copied, assigned and compared. 
        The first two points have been in the C++ language from the beginning and this 
        proposal attempts to address the last one.

        <p>I want to thank Andrew Sutton for early feedback and guidance as well as
           Daniel Krügler for detailed corrections and suggestions.

</body></html>
