<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <title>Evolution of the P0443 Unified Executors Proposal to accommodate new requirements</title>
  <style type="text/css">
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
  </style>
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  <style type="text/css">
      h1.title {display:none}
      ins {color:#00A000}
      ins p code {color:#00A000}
      p ins code {color:#00A000}
      del {color:#A00000}
      del p code {color:#A00000}
      p del code {color:#A00000}
      blockquote {border-left:0.4em solid #C0C0C0; padding-left:0.2em}
      table, th, td {border:1px solid #C0C0C0}
  </style>
</head>
<body>
<header>
<h1 class="title">Evolution of the P0443 Unified Executors Proposal to accommodate new requirements</h1>
</header>
<pre>
Document number: D1791r0
Date:            2019-06-16
Project:         Programming Language C++
Audience:        SG1
Reply-to:        Christopher Kohlhoff &lt;chris {at} kohlhoff_dot_com&gt;
                 Jamie Allsop &lt;jamie.allsop {at} clearpool_dot_io&gt;
</pre>
<h1 id="evolution-of-the-p0443-unified-executors-proposal-to-accommodate-new-requirements">Evolution of the P0443 Unified Executors Proposal to accommodate new requirements</h1>
<h2 id="introduction">Introduction</h2>
<p>This paper proposes an updated consensus design for executors as a revision of the existing consensus paper <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0443r10.html">A Unified Executors Proposal for C++, P0443r10</a> which incorporates, or explicitly addresses as appropriate, new requirements which have emerged since that paper was produced. The follow-up to this paper would be a revision 11 of <a href="http://wg21.link/P0443">P0443r10</a>.</p>
<h2 id="recap-on-what-p0443-presents">Recap on what P0443 presents</h2>
<p><a href="http://wg21.link/P0443">P0443</a> establishes:</p>
<ul>
<li>core concepts to represent task submission, and</li>
<li>facilities to allow interoperability between otherwise disparate domain models that require executors.</li>
</ul>
<p>Importantly, <a href="http://wg21.link/P0443">P0443</a> does not seek to specify high level control structures (such as algorithms), but rather provide a foundation for building these structures.</p>
<p>This is achieved by standardising a vocabulary of well-known <a href="http://wg21.link/P1393">properties</a> related to execution. This in itself is extensible to accommodate future expansion of this standardised vocabulary, and also facilitates the expression of domain-specific, and indeed application-specific, requirements.</p>
<h2 id="framing-the-discussion">Framing the discussion</h2>
<p>The debates and efforts surrounding the standardisation of executors has been a long journey with many participants, starting in earnest back in 2012, but has origins well before that with different use cases motivating disparate views on what the “one true” executor abstraction should look like.</p>
<p>A number of distinct proposals emerged from that initial work, each with important but differing views on the best way forward, motivated by their different use cases and core requirements. At that time one option could have been to allow each to continue evolution in relative isolation with a view to eventual standardisation of multiple related, but distinct, executor abstractions. However, the view of SG1 was that a single executor abstraction was preferred, and so direction was given to the authors of the various proposals to make an effort to find a consensus proposal that would allow the standardisation of that single, or more precisely, unified abstraction.</p>
<p>After many months of discussion and debate an initial revision of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0443r0.html">A Unified Executors Proposal for C++, P0443</a> was produced, in late 2016. Then in 2017 the <a href="http://wg21.link/P0761">Executors Design Document</a> was produced as a companion document to <a href="http://wg21.link/P0443">P0443</a> to capture and document the design decisions that underpinned the work in <a href="http://wg21.link/P0443">P0443</a>.</p>
<p>Since that <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0443r0.html">initial version</a>, <a href="http://wg21.link/P0443">P0443</a> has undergone 10 revisions, taking onboard the views from a large body of experts representing both their respective view points, their industries and domains, and their companies. This has included such organisations and groups as Google, Sandia National Labs, Codeplay, Facebook, Nasdaq, Clearpool.io, Nvidia, Stellar Group, Microsoft, RedHat, HPX, HPC, and domains such as Ultra Low Latency Finance, Embedded Systems, APU, GPU, SYCL, Networking, Machine Learning, Library Development and Big Data to name a few.</p>
<p>In addition many more have influenced the paper through discussions at standards meetings and other mediums. In all more than 100 papers and revisions have been produced that either directly or indirectly have significantly impacted the consensus position represented by <a href="http://wg21.link/P0443">P0443</a>.</p>
<p>In summary <a href="http://wg21.link/P0443">P0443</a> represents a significant body of compromise and consensus seeking. When the parties represented by <a href="http://wg21.link/P0443">P0443</a> began their journey, we all saw our own requirements as essential and therefore universally applicable. As a result initial compromises were focused on gaining buy-in from other parties that those requirements were in fact universal and should be accepted as such. A significant part of the consensus building experience was to realise that while they may be essential in a particular domain, they were not universal and so some method of satisfying that reality needed to be found.</p>
<p>As a result <a href="http://wg21.link/P0443">P0443</a> represents a unified set of building blocks and the tools to assemble them, and not, as some may prefer, a set of high level control structures. The intention is that those high level control structures, which are likely to be more domain specific, should be layered on top.</p>
<p>In more recent times (mid 2018) we have had additional requirements put forward starting with paper <a href="http://wg21.link/P1055">P1055</a>, with the culmination of those additional requirements to be found in <a href="http://wg21.link/P1660">P1660</a> - found in the same mailing as this paper.</p>
<p>The authors of this paper believe that these requirements represent additional evidence of the value of the approach stipulated in <a href="http://wg21.link/P0443">P0443</a> and this paper will demonstrate how those requirements can be met using the facilities of <a href="http://wg21.link/P0443">P0443</a>.</p>
<p>This is important because there is a danger that the specific needs of <a href="http://wg21.link/P1660">P1660</a> will inadvertently be given precedence over the existing and extensive compromises that have been made in order to reach the consensus position that is <a href="http://wg21.link/P0443">P0443</a>. In other words we should, if at all possible, identify if the requirements identified in <a href="http://wg21.link/P1660">P1660</a> can be satisfied by <a href="http://wg21.link/P0443">P0443</a> and then if we cannot satisfy them directly we should explore what is deficient with <a href="http://wg21.link/P0443">P0443</a> that makes that the case and then address those deficiencies as requirements for <a href="http://wg21.link/P0443">P0443</a>.</p>
<p>Said another way the default starting point should be to assume that the status quo consensus can meet the requirements of <a href="http://wg21.link/P1660">P1660</a>, and then investigate how, and whether they can (or cannot) do so.</p>
<p>In fact the properties mechanism that was surfaced as part of the consensus journey of <a href="http://wg21.link/P0443">P0443</a> was developed precisely to address this situation: that not all domains have the same requirements but they need a way to express those requirements as first class vocabulary elements in their executor domain models.</p>
<p>The approach that most of the parties take is to express these additional requirements as properties, and to encapsulate them in a single place using a domain-specific control structure. Thus the approach for integrating new use cases into the <a href="http://wg21.link/P0443">P0443</a> executor framework should be to:</p>
<ul>
<li>Identify what additional properties, if any, are required to support the domain specific requirements</li>
<li>Define domain-specific control structures that encapsulate the use of those properties</li>
</ul>
<p>Feedback from Rapperswil was that <a href="http://wg21.link/P0443">P0443</a> had too many concepts, and that we should find a way to minimise those concepts. This paper represents the end of that journey with simplification to a single Executor concept (which incidentally is inline with one of the requirements identified in <a href="http://wg21.link/P1660">P1660</a>). Specifically the <code>OneWayExecutor</code> concept renamed to simply <code>Executor</code>, is now the consensus based fundamental executor concept.</p>
<h2 id="the-requirements-gap-with-p1660">The requirements gap with P1660</h2>
<p>In essence <a href="http://wg21.link/P1660">P1660</a> elaborates the requirements for executors as a low-level primitive for a <code>Sender/Receiver</code> framework and therefore it is these requirements that we need to explore the viability of in the context of <a href="http://wg21.link/P0443">P0443</a>.</p>
<p>Through assessing <a href="http://wg21.link/P1660">P1660</a> in this context, and supplemented by clarifications with the authors, we can observe that the following requirement gaps are now closed:</p>
<ul>
<li>oneway executor as a primitive for <code>Sender/Receiver</code>s. <a href="http://wg21.link/P1660">P1660</a> recognises that this is a suitable primitive.</li>
</ul>
<p>However the following requirements exist and are not aligned directly with <a href="http://wg21.link/P0443">P0443</a>. Namely that <a href="http://wg21.link/P1660">P1660</a> requires:</p>
<ul>
<li>A channel for signalling when an error occurs after task submission but prior to task execution.</li>
<li>A channel to signal when a task is unstaged without execution.</li>
</ul>
<p>The motivation behind these two requirements is to make it easier to support the higher level <code>Sender/Receiver</code> design in a way that better satisfies their executor usage requirements.</p>
<p>The proposal presented in <a href="http://wg21.link/P1660">P1660</a> then seeks to address these requirements by:</p>
<ul>
<li>Defining concepts <code>CallbackSignal</code> and <code>Callback</code> that associate an error channel with a submitted task.</li>
<li>Specifying that all models of the Executor concept must be aware of these concepts. If a submitted function object models <code>Callback</code> then the Executor shall detect this at compile time and deliver the two signals described above to the function object.</li>
</ul>
<p>This approach imposes a burden on all Executor types in order to satisfy these new requirements. This runs counter to the experience of developing consensus in the design of <a href="http://wg21.link/P0443">P0443</a>, where a key lesson was that while we each have requirements that are key to ones own use cases, these requirements are not universal.</p>
<p>While we recognise the validity of these new requirements, we believe that they can and should be addressed using the existing facilities and approaches contained with <a href="http://wg21.link/P0443">P0443</a>.</p>
<h2 id="p0443-can-support-the-additional-requirements-of-p1660">P0443 can support the additional requirements of P1660</h2>
<p>To qualify earlier statements we believe that we will want to define a control structure as the primary interface for user experience (where user includes authors of algorithms). Let us say that this new control structure is a function named <code>submit</code>. This is in line with <a href="http://wg21.link/P1660">P1660</a>. For exposition only (readers should refer to <a href="http://wg21.link/P1660">P1660</a> for a more detailed discussion):</p>
<pre><code>template&lt;Callback C, Executor&lt;C&gt; E&gt;
void std::tbd::submit(E&amp;&amp; e, C&amp;&amp; c);</code></pre>
<p>The question then is how would this be provided in the context of <a href="http://wg21.link/P0443">P0443</a>? In fact there are several approaches that could be adopted (or combination of approaches) that would offer this higher level control structure while satisfying:</p>
<ul>
<li>the needs outlined in <a href="http://wg21.link/P1660">P1660</a>, namely the support for error and done signals, and,</li>
<li>the general design goals of <a href="http://wg21.link/P0443">P0443</a>, namely that domain specific needs should not be forced onto other domains unnecessarily.</li>
</ul>
<p>More specifically there are at least four approaches to provide the necessary support for this control structure. We could:</p>
<ol type="1">
<li>Define a property to represent each interesting callback signal.</li>
<li>Define an “enumerated” property set to describe possible error handling strategies.</li>
<li>Define <code>submit</code> as a customisation point object, with an associated property type to allow the customisation to be propagated through a polymorphic executor wrapper.</li>
<li>Define a callback-based executor as its own concept, and use <code>require_concept</code> to provide the means to generically convert executors to this concept.</li>
</ol>
<p>All of these are viable implementation approaches, however the first two are most consistent with the design of <a href="http://wg21.link/P0443">P0443</a> that encourages employing properties as a mechanism to build a vocabulary or toolkit.</p>
<h3 id="approach-1-define-a-property-to-represent-each-signal">Approach 1: define a property to represent each signal</h3>
<p>In this implementation approach, each interesting signal is represented by a corresponding property. For example, an error notification signal would have a property <code>on_error_t</code> that is specified as follows:</p>
<pre><code>template &lt;class Handler&gt;
struct on_error_t
{
  template &lt;class T&gt;
    static constexpr bool is_applicable_property_v;

  static constexpr bool is_requirable = true;

  template &lt;class E&gt;
    static constexpr auto static_query_v
      = Executor::query(allocator_t);

  constexpr on_error_t();
  template &lt;class OtherHandler&gt;
    constexpr on_error_t(const on_error_t&lt;OtherHandler&gt;&amp; other);
  constexpr explicit on_error_t(Handler h);

  template &lt;class OtherHandler&gt;
    constexpr on_error_t&lt;OtherHandler&gt; operator()(OtherHandler h) const

  constexpr Handler value() const;

private:
  Handler handler_; // exposition only
};

constexpr on_error_t&lt;/* ... */&gt; on_error;</code></pre>
<p>This property is used to associate a handler for the error signal. To satisfy the requirements embodied by <a href="http://wg21.link/P1660">P1660</a>, this handler must be noexcept invocable, and when invoked is passed:</p>
<ul>
<li>a reference to the submitted function object; and</li>
<li>the error</li>
</ul>
<p>This gives the user an opportunity to propagate the error directly to the submitted task, or perhaps to instead treat error handling as a cross cutting concern.</p>
<pre><code>auto ex1 = pool.executor();

auto ex2 = std::require(ex1,
    execution::on_error(
      [](auto&amp; f, auto e) noexcept
      {
        f.error(e);
      }
    )
  );

struct my_task
{
  void operator()();
  template &lt;class E&gt; void error(E) noexcept;
  void done() noexcept;
};

ex2.execute(my_task{});</code></pre>
<p>A similar property <code>on_done_t</code> could be specified for the “done” signal.</p>
<p>To support polymorphic wrappers, these properties have counterparts <code>polymorphic_on_error_t</code> and <code>polymorphic_on_done_t</code> that perform the necessary type erasure to propagate the signals through a polymorphic wrapper. These properties would automatically convert to their type-safe equivalents, so that users only need to use the type-safe property, as shown below:</p>
<pre><code>execution::executor&lt;
  execution::polymorphic_on_error_t,
  /* other properties */
&gt; ex3 = ex2;

auto ex4 = std::require(ex1,
    execution::on_error(
      [](auto&amp; f, auto e) noexcept
      {
        f.error(e);
      }
    )
  );

ex4.execute(my_task{});</code></pre>
<p>This approach is similar to that already used in <a href="http://wg21.link/P0443">P0443</a> for the allocator property. Other examples of signals that might use this approach include: polling for task cancellation, flow control (such as overflow and underflow events), and exception reduction functions.</p>
<h3 id="approach-2-define-a-set-of-properties">Approach 2: define a set of properties</h3>
<p>An alternative approach is to provide a set of enumerated properties that represent a set of available error handling strategies for Executors. This may include “enumerator” properties with names such as <code>unspecified</code> or <code>terminate</code>.</p>
<p>One of those property “enumerators” may be called <code>propagate_to_callback</code> which, if present, indicates that the Executor will test for some well-known concept <code>Callback</code> and, if the concept is detected, capture errors and propagate them to the callback.</p>
<p><a href="http://wg21.link/P0797">P0797, Handling Concurrent Exceptions with Executors</a> explores this design space further.</p>
<p>Note that both the approaches outlined above are not necessarily mutually exclusive.</p>
<h3 id="using-property-based-submit-in-generic-code">Using property-based submit in generic code</h3>
<p>As discussed in <a href="http://wg21.link/P0761">P0761, the Executors Design Document</a>, and reiterated above we expect that most users will not interact with executors directly, but rather through some kind of control structure (of which algorithms may be an instance).</p>
<p>With that in mind, users who wish to traffic in <code>Callback</code> types (as described in <a href="http://wg21.link/P1660">P1660</a>), would submit their callbacks for execution using either their own, or as <a href="http://wg21.link/P1660">P1660</a> implies, a standardised <code>submit</code> function. A simplistic exposition of <code>submit</code> would be:</p>
<pre><code>template &lt;Executor E, Callback C&gt;
void submit(E e, C c)
{
  std::require(std::move(e),
      std::execution::on_error(
        [](auto&amp; c, auto e)
        {
          c.error(e);
        }
      ),
      std::execution::on_done(
        [](auto&amp; c)
        {
          c.done();
        }
      )
    ).execute(std::move(c));
}</code></pre>
<p>As <code>on_error</code> and <code>on_done</code> are specified as properties, whether they are supported for a particular Executor is an explicit opt-in on the part of that Executor.</p>
<p>Furthermore, as a user of executors we are able to test for their supportability on a particular Executor by using <code>can_require_v</code>. A more complete exposition of <code>submit</code> might therefore be:</p>
<pre><code>template &lt;Executor E, Callback C&gt;
void submit(E e, C c)
{
  auto error_handler = [](auto&amp; c, auto e) noexcept
  {
    std::move(c).error(std::move(e));
  };

  auto done_handler = [](auto&amp; c) noexcept
  {
    std::move(c).error();
  };

  if constexpr (
      std::can_require_v&lt;E, std::execution::on_error_t&lt;decltype(error_handler)&gt;&gt; &amp;&amp;
      std::can_require_v&lt;E, std::execution::on_done_t&lt;decltype(done_handler)&gt;&gt;
    )
  {
    std::require(std::move(e),
        std::execution::on_error(error_handler),
        std::execution::on_done(done_handler)
      ).execute(std::move(c));
  }
  else
  {
    // Fallback to an alternative method...
  }
}</code></pre>
<p>This second formulation would allow <code>submit</code> to be used generically across all executor types, but from a pure user experience viewpoint they traffic in the vocabulary of <code>submit</code>, while executor authors are free to establish whatever constraints or freedoms they require to satisfy their domain requirements and provide a custom <code>submit</code> (or other more appropriate control structure) should the standard <code>submit</code> not meet their needs.</p>
<h2 id="standardising-submit-callbacksignal-and-callback">Standardising submit, CallbackSignal and Callback</h2>
<p>While the specification of the <code>submit</code> control structure is outside the scope of this paper, we expect that it, and its supporting concepts <code>CallbackSignal</code> and <code>Callback</code>, would be standardised as vocabulary elements to support the development of generic algorithms that rely on this behaviour, as inferred by <a href="http://wg21.link/P1660">P1660</a>.</p>
<h2 id="outline-of-proposed-changes-to-p0443-for-a-revision-11">Outline of proposed changes to P0443 for a Revision 11</h2>
<p>These changes are relative to <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0443r10.html">P0443r10</a>:</p>
<ul>
<li>Remove the existing <code>is_executor</code> trait, the <code>is_executor_v</code> variable template, and all <code>is_executor_v</code> members.</li>
<li>Rename the <code>OneWayExecutor</code> type requirements to <code>Executor</code>.</li>
<li>Rename the <code>is_oneway_executor</code> trait to <code>is_executor</code>, and corresponding <code>is_oneway_executor_v</code> variable template to <code>is_executor_v</code>.</li>
<li>Remove the <code>is_bulk_oneway_executor</code> trait and <code>is_bulk_oneway_executor_v</code> variable template.</li>
<li>Remove the interface changing properties <code>oneway_t</code> and <code>bulk_oneway_t</code>.</li>
<li>Consolidate the polymorphic wrapper in its oneway form as class template <code>executor&lt;&gt;</code>.</li>
<li>Remove the <code>require_concept</code> member, and all uses of <code>can_require_concept_v</code>, from the polymorphic wrapper.</li>
<li>Remove the <code>static_executor_cast</code> member from the polymorphic wrapper.</li>
<li>Combine the specification for <code>static_thread_pool</code> executor types with the <code>execution::oneway</code> property into the general specification of all <code>static_thread_pool</code> executor types.</li>
<li>Remove the specification for <code>static_thread_pool</code> executor types with the <code>execution::bulk_oneway</code> property.</li>
<li>Add a new property <code>on_error_t</code>.</li>
<li>Add a new property <code>polymorphic_on_error_t</code>.</li>
<li>Add a new property <code>on_done_t</code>.</li>
<li>Add a new property <code>polymorphic_on_done_t</code>.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>In summary this paper seeks to:</p>
<ul>
<li>reaffirm the importance of recognising the extensive consensus and compromise embodied in the <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0443r10.html">Unified Executors Proposal for C++, P0443r10</a> paper.</li>
<li>recap the value and benefits of seeking to accommodate new requirements against the existing extensibility facilities offered by <a href="http://wg21.link/P0443">P0443</a> whose primary purpose is to facilitate this kind of adaption and customisation.</li>
<li>assert that while the additional requirements of <a href="http://wg21.link/P1660">P1660</a> have recognisable value for the target use cases they do, as implemented in <a href="http://wg21.link/P1660">P1660</a>, impose unnecessary burden on executor authors of other domains. More directly, as implemented they break one of the key design goals of <a href="http://wg21.link/P0443">P0443</a> which was specifically to support scenarios like this where it is recognised not all requirements are, or should be treated as, universal.</li>
<li>demonstrate that the requirements of <a href="http://wg21.link/P1660">P1660</a> can be met by <a href="http://wg21.link/P0443">P0443</a> with minor extensions to the vocabulary of standardised properties and without breaking the design goals of <a href="http://wg21.link/P0443">P0443</a>.</li>
</ul>
<p>The next steps would be to issue a new revision of P0443 that reflects these changes, and to work with the authors of P1660 to specify standardese for <code>submit</code> and related control structures.</p>
</body>
</html>
