<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
  <head>
    <meta content="text/html;charset=UTF-8" http-equiv="Content-Type">
    <title>Deprecate Implicit Capture of this</title>
    <style type="text/css">
      html { margin: 0; padding: 0; color: black; background-color: white; }
      body { padding: 2em; font-size: medium; font-family: "DejaVu Serif", serif; line-height: 150%; }
      code { font-family: "DejaVu Sans Mono", monospace; color: #006; }

      h1, h2, h3 { margin: 1.5em 0 .75em 0; line-height: 125%; }

      div.code { white-space: pre-line; font-family: "DejaVu Sans Mono", monospace;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1em;
                 border-radius: 4px; }

      div.strictpre { white-space: pre; }

      sup, sub { line-height: 0; }

      .docinfo { float: right; }
      .docinfo p { margin: 0; text-align:right; }
      .docinfo address { font-style: normal; }

      .quote { display: inline-block; clear: both; margin-left: 1ex;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1ex; }

      .modify { border-left: thick solid #999; border-right: thick solid #999; padding: 0 1em; }
      .insert { border-left: thick solid #0A0; border-right: thick solid #0A0; padding: 0 1em; }
      .comment { color: #456; }

      table { border-top: 2px solid black; border-bottom: 2px solid black; border-collapse: collapse; margin: 3em auto; }
      thead th { border-bottom: 2px solid black; }
      th, td { text-align: left; padding: 1ex 1ex 1ex 5em; }
      th:first-child, td:first-child { padding-left: 1ex; }

      p.skip { margin-top: 1em; }

      ins { color: #090; }
      del { color: #A00; }
      ins code, del code { color: inherit; }
    </style>
  </head>
  <body>
    <div class="docinfo">
      <p>Date: 2017-10-08</p>
      <address>Thomas K&ouml;ppe &lt;<a href="mailto:tkoeppe@google.com">tkoeppe@google.com</a>&gt;</address>
      <p class="skip">ISO/IEC JTC1 SC22 WG21 P0806r0</p>
      <p>To: EWG</p>
    </div>

    <h1>Deprecate Implicit Capture of <code>this</code></h1>

    <!-- fgrep -e "<h2 id=" deprecate_this.html | sed -e 's/.*id="\(.*\)">\(.*\)<\/h2>/<li><a href="#\1">\2<\/a><\/li>/g' -->
    <h2>Contents</h2>
    <ol>
      <li><a href="#history">Revision history</a></li>
      <li><a href="#summary">Summary</a></li>
      <li><a href="#discussion">Discussion</a></li>
      <li><a href="#wording">Proposed wording</a></li>
      <li><a href="#polls">Poll suggestions and early feedback</a></li>
      <li><a href="#future">Future directions</a></li>
      <li><a href="#compat">Compatibility, upgrade path, warnings</a></li>
    </ol>

    <h2 id="history">Revision history</h2>
    <ul>
      <li>P0806r0: Initial proposal.</li>
    </ul>

    <h2 id="summary">Summary</h2>

    <p>We propose to deprecate the implicit capture of <code>this</code> in a lambda expression
      with a <em>capture-default</em>. Users should explicitly use one of <code>[&amp;, this]</code>,
      <code>[&amp;, *this]</code>, <code>[=, this]</code> or <code>[=, *this]</code>.</p>

    <table>
      <col style="width: 37em">
      <col style="width: 42em">

      <thead>
        <tr><th>Before the proposal</th><th>With the proposal</th></tr>
      </thead>

      <tbody>
        <tr>
          <td><div class="code">struct Foo {
              &nbsp; int n = 0;
              &nbsp; void f(int a) {
              &nbsp; &nbsp; g(<span style="color: #A00">[&amp;, a]</span>(int k) { n += a * k; });
              &nbsp; &nbsp; g(<span style="color: #A00">[=]</span>(int k) { return n + a * k; });
              &nbsp; &nbsp; g([=, *this](int k) { return n + a * k; });
              &nbsp; }
              };</div></td>
          <td><div class="code">struct Foo {
              &nbsp; int n = 0;
              &nbsp; void f(int a) {
              &nbsp; &nbsp; g(<span style="color: #0A0">[&amp;, this, a]</span>(int k) { n += a * k; });
              &nbsp; &nbsp; g(<span style="color: #0A0">[=, this]</span>(int k) { return n + a * k; });
              &nbsp; &nbsp; g([=, *this](int k) { return n + a * k; });
              &nbsp; }
              };</div></td>
        </tr>
      </tbody>
    </table>

    <h2 id="discussion">Discussion</h2>

    <p>There are two kinds of default capture in a lambda expression:</p>
    <ul>
      <li><code>[&amp;]</code>: names in the lambda body refer to the actual entities that they name.</li>
      <li><code>[=]</code>: names in the lambda body refer to local data members of the closure object that
        were copied from the entities in the surrounding scope.</li>
    </ul>

    <p>When the lambda expression occurs inside a non-static class member function, any name <code>foo</code>
      of a non-static class member is interpreted as <code>this-&gt;foo</code>, where <code>this</code> is now
      bound to a local data member of the closure object. This copy is initialised from the value of <code>this</code>
      of the surrounding class member function <em>for both kinds of default capture</em>.</p>

    <p>This situation is somewhat surprising and irregular. The semantics of capture-by-reference
      suggest that class members should refer directly to class members of the containing object.
      On the other hand, <code>this</code> is a pointer value, and it is clearly itself <em>copied</em>
      into the closure object. So whichever way one looks at the capture, one can rationalise for both
      <code>[&amp;]</code> and <code>[=]</code> that they cause a copy of <code>this</code> to be
      stored in the closure object. By contrast, neither capture default effects the capture of
      <code>[*this]</code>, which would copy the entire containing object into the closure object and
      rebind <code>this</code> to point to that copy.</p>

    <p>At this point, some historic background is helpful. The <code>this</code> keyword was
      introduced to C++ before references. At the time, C++ was translated into C, and the
      simple pointer semantics of <code>this</code> were convenient. If the entire feature set
      of references, value categories and classes had been designed together, <code>this</code>
      would have been an lvalue designating the object, and not a prvalue designating the
      address of the object. We can adopt this historic perspective by thinking of the fundamental
      object as &ldquo;<code>*this</code>&rdquo; rather than <code>this</code>. Let us consider
      how we might capture this object:</p>

    <ul>
      <li>Capture <code>*this</code> by value: <code>[*this]</code></li>
      <li>Capture <code>*this</code> by reference: hypothetically we would say
        &ldquo;<code>[&amp;*this]</code>&rdquo;; in C++ we say <code>[this]</code></li>
      <li>If the default capture is reference capture, the hypothetical &ldquo;<code>[&amp;, &amp;*this]</code>&rdquo;
        (in real C++: <code>[&amp;, this]</code>) is a redundant reference capture; <code>[&amp;, *this]</code> is
        a non-redundant value capture.</li>
      <li>If the default capture is value capture, the hypothetical &ldquo;<code>[=, &amp;*this]</code>&rdquo;
        (in real C++: <code>[=, this]</code>) is a non-redundant reference capture; <code>[&amp;, *this]</code> is
        a redundant value capture.</li>
    </ul>

    <p>In C++14, the fact that both default captures captured the <code>this</code> pointer was
      perhaps peculiar, but unambiguous. But C++17 added genuine value-capture of the containing
      object via <code>[*this]</code>, so that it is now more surprising that <code>[=]</code>
      means <code>[=, this]</code> and not <code>[=, *this]</code>. In other words, one default
      capture (<code>[&amp;]</code>) captures <code>*this</code> in the way that would be redundant
      when spelled out, but the other capture (<code>[=]</code>) captures it in the non-redundant
      way.</p>

    <p>This inconsistency in defaults is confusing. Users may well know that there <em>exists</em>
      an inconsistency, but it is much harder to know which way round the inconsistency goes.
      For this reason, we propose that users should never rely on implicit capture of <code>*this</code>,
      whether by reference or by value, and always spell out explicitly which form they want:</p>
    <ul>
      <li><code>[=]</code> &rarr; <code>[=, &nbsp;this]</code>: local variables by value, class members by reference</li>
      <li><code>[=]</code> &rarr; <code>[=, *this]</code>: everything by value</li>
      <li><code>[&amp;]</code> &rarr; <code>[&amp;, &nbsp;this]</code>: everything by reference</li>
      <li><code>[&amp;]</code> &rarr; <code>[&amp;, *this]</code>: (this would be unusual)</li>
    </ul>

    <p>A diminished form of this proposal would be to only deprecate the implicit capture
      of <code>this</code> by a <code>[=]</code>-capture, since the reference capture is
      unambiguous and unsurprising. However, we believe that in a codebase that contains
      all kinds of captures, if only one version had an implicit capture and all the others
      did not, it would be more confusing to remember what the one exception was than if
      all captures would just be explicit.</p>

    <h2 id="wording">Proposed wording</h2>

    <p>Append a sentence to [8.1.5.2 expr.prim.lambda.capture]p7:</p>
    <div class="modify">
      A <em>lambda-expression</em> with an associated
      <em>capture-default</em> that does not explicitly capture <code>*this</code> or
      a variable with automatic storage duration (this excludes any <em>id-expression</em>
      that has been found to refer to an <em>init-capture</em>&rsquo;s associated
      implicit capture non-static data member), is said to <em>implicitly capture</em>
      the entity (i.e., <code>*this</code> or a variable) if the <em>compound-statement</em>:
      <ul>
        <li>odr-uses (6.2) the entity (in the case of a variable),</li>
        <li> odr-uses (6.2) <code>this</code>
          (in the case of the object designated by <code>*this</code>), or</li>
        <li>names the entity in a potentially-evaluated expression (6.2) where the enclosing full-expression depends on
          a generic lambda parameter declared within the reaching scope of the
          <em>lambda-expression</em>.</li>
      </ul>
      <ins>The implicit capture of <code>*this</code> is deprecated; see D.?.</ins>
    </div>

    <p>Insert a new section [D, depr], between the current [D.3, depr.except.spec] and [D.4, depr.cpp.headers].</p>
    <div class="insert">
      <h3><ins>D.? Implicit capture of <code>*this</code> by reference [depr.capture.this]</ins></h3>
      <p><ins>For compatibility with prior C++ International Standards, a lambda expression with
        <em>capture-default</em> <code>&amp;</code> or <code>=</code> ([8.1.5.2, expr.prim.lambda.capture])
        can capture <code>*this</code> by reference implicitly.</ins></p>
    </div>

    <h2 id="polls">Poll suggestions and early feedback</h2>

    <p>Feedback from the reflector on a draft of this proposal included concerns that the
      deprecation of <code>[&amp;]</code> to mean <code>[&amp;, this]</code> would break useful
      code in a way that has no easy upgrade, for example macros that expand to lambdas that
      capture everything by reference.</p>
    <p>The following two polls would provide valuable guidance.</p>
    <p><strong>Poll:</strong> <em>Proposal as is: should we deprecate the implicit capture of <code>*this</code> by reference?</em></p>
    <p><strong>Poll:</strong> <em>Should we deprecate <code>[=]</code> to mean <code>[=, this]</code> (but leave <code>[&amp;]</code> untouched)?</em></p>

    <h2 id="future">Future directions</h2>

    <p>The obvious next step would be to make the implicit capture of <code>*this</code> ill-formed.
      This could only happen post-C++20, since valid C++17 code must first upgrade to C++20 by
      changing <code>[=]</code> to <code>[=, this]</code>, which is ill-formed in C++17 (added by
      <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0409r2.html">P0409R2</a>).
      The meaning of <code>[=]</code> could then be changed again in the farther future. Such a
      change would presumably affect a large amount of use cases, but the upgrade path is
      straight-forward. Alternatively, the feature could simply remain deprecated to guide
      users to avoid implicit capture of <code>*this</code> in new code.</p>

    <h2 id="compat">Compatibility, upgrade path, warnings</h2>

    <p>Let us briefly examine the upgrade path and compiler warnings that would likely result
      from this proposed change, in the spirit
      of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0684r0.pdf">P0684</a>.
      The change does not break otherwise valid C++20 code, and the earliest revision in which a
      breakage from C++17 could appear is C++23. Therefore compilers for the current standard
      (C++17) need not emit <em>any</em> warning, but at best it would be a &ldquo;future
      deprecation&rdquo; warning rather than a &ldquo;future breakage&rdquo; warning. In C++20
      conformance mode, compilers may reasonably emit a deprecation warning by default, or they
      could defer any warnings to the &ldquo;future breakage&rdquo; kind if and when a proposal
      for a breaking change is accepted. The replacement <code>[=, this]</code> for the
      deprecated <code>[=]</code> is ill-formed in C++17 and only available in C++20 as
      of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0409r2.html">P0409r2</a>.</p>

  </body>
</html>
