1. Introduction
In Fall 2020, the C++ Library Evolution group took a series of electronic decision polls [P2233R3]. This paper provides the results of those polls and summarizes the results.
In total, 49 people participated in the polls. Some participants opted to not vote on some polls. Thank you to everyone who participated, and to the proposal authors for all their hard work!
2. Summarized Poll Results
Poll | SF | WF | N | WA | SA | Outcome |
---|---|---|---|---|---|---|
Poll 0: Remove implicit adaptation from [P0443R14] (Executors) by applying [P2235R0] to [P0443R14], which will make only take s,
make only take s, make and operations
like only take s and s, and add explicit
adaptation from to ( )
but not vice versa.
| 21 | 15 | 0 | 0 | 0 | Unanimous consensus in favor. |
Poll 1: Use one class for each individual trait instead of combined traits
classes ( , etc) in [P0443R14] (Executors).
| 7 | 7 | 7 | 5 | 2 | No consensus. |
Poll 2: Remove from [P0443R14] (Executors).
It may be pursued in a follow-on proposal.
| 8 | 11 | 4 | 7 | 2 | Weak consensus in favor. |
Poll 3: Remove from [P0443R14] (Executors).
It may be pursued in a follow-on proposal.
| 10 | 9 | 4 | 4 | 2 | Consensus in favor. |
Poll 4: Remove and from [P0443R14] (Executors).
| 12 | 10 | 4 | 2 | 0 | Consensus in favor. |
Poll 5: [P0443R14] (Executors) is sufficiently mature that we should aim to ship it in C++23. | 10 | 12 | 7 | 10 | 1 | Weak consensus in favor. |
Poll 6: Send [P2212R1] (Relax Requirements for ) to LWG
for C++23, classified as an improvement of an existing feature ([P0592R4] bucket 2 item).
| 18 | 13 | 3 | 0 | 0 | Strong consensus in favor. |
Poll 7: Send [P2166R1] (Prohibit and Construction from ) to LWG for C++23, classified as an improvement
of an existing feature ([P0592R4] bucket 2 item).
| 15 | 18 | 2 | 2 | 1 | Consensus in favor. |
Poll 8: Send [P2161R2] (Remove Default Candidate Executor) to LWG for the Networking TS P-numbered Working Draft, classified as a focus work item ([P0592R4] bucket 1 item). | 6 | 14 | 2 | 2 | 0 | Consensus in favor. |
3. Summarized Outcomes
Revise [P0443R14] (Executors) as follows and return to Library Evolution for further review:
-
Apply [P2235R0].
-
Remove
. A separate follow-on proposal forstatic_thread_pool
is encouraged.static_thread_pool -
Remove
. Ifany_executor
is pursued in the future,any_executor
andany_executor :: target
shall be removed.any_executor :: target_type
We will continue on our planned course of aiming to ship [P0443R14] (Executors) in C++23, but a notable minority in Library Evolution are not convinced that [P0443R14] (Executors) is sufficiently mature. Library Evolution wants to see more field experience with [P0443R14] (Executors). P0443R14 (Executors) authors and advocates should take note of this. Focus on demonstrating field experience through implementations and usage, improving introductory material, minimizing the scope, resolving outstanding minor open issues, and developing wording to increase Library Evolution confidence in the maturity of [P0443R14] (Executors).
We encourage a separate follow-on proposal exploring individual traits versus combined traits classes in general, using [P0443R14] (Executors) as an example to gauge impact.
[P2212R1] (Relax Requirements for
) is sent LWG for C++23,
classified as an improvement of an existing feature ([P0592R4] bucket
2 item).
[P2166R1] (Prohibit
and
Construction
from
) is sent to LWG for C++23, classified as an improvement of an
existing feature ([P0592R4] bucket 2 item).
[P2161R2] (Remove Default Candidate Executor) is sent to LWG for the Networking TS Working Draft, classified as a focus work item ([P0592R4] bucket 1 item).
4. Detailed Poll Results and Selected Comments
4.1. Executor Polls
The following C++ Library Evolution polls relate to executors ([P0443R14]), a proposed set of abstractions for asynchronously creating and managing execution agents.
4.1.1. Poll 0
Remove implicit adaptation from [P0443R14] (Executors) by applying [P2235R0] to [P0443R14]) which will:
-
Make
only takeschedule
s.scheduler -
Make
only takeexecute
s.executor -
Make sender and receiver operations like
only take senders and receivers.connect -
Add explicit adaptation from
toexecutor
(scheduler
) but not vice versa.make_scheduler_from_executor
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
21 | 15 | 0 | 0 | 0 |
4.1.1.1. Outcome
Unanimous consensus in favor.
We will need to continue discussing explicit adaptation, the relationship
between
and
and the implications of bifurcation on the
ecosystem.
4.1.1.2. Selected Comments
I feel unable to support moving this proposal forward since I still find it next to impossible to understand what’s going on, despite extensive discussion and leading a review group.
— Did Not Vote
[Implicit adaptation] adaption was the biggest issue with [P0443R14]!
— Strongly Favor
This is a step in the right direction. I think additional simplifications are possible and desirable, but I am happy with this direction.
— Strongly Favor.
The circularity between
and
execution :: execute is complicated and must be eliminated. However, the resulting disconnection between
execution :: connect s and
executor s is a bug that must be addressed.
scheduler — Strongly Favor
This is fine, though it may result in some awkwardness when forming overloads that accept both a scheduler and an executor.
— Weakly Favor
I think that the [P2235R0] suggestions are good overall. Removing implicit adaptations should make things clearer. Currently there are places where the behavior of customization points is not obvious due to all of those implicit adaptation features. However, I still think that there are different opinions about which notion is the base one:
or
scheduler . To me it’s
executor . I believe we already discussed that fire-and-forget semantics can be implemented via schedulers. On the other hand, executors don’t support chaining and error handling in a manner how schedulers do that. That’s why schedulers look more fundamental IMO. I could easily imagine
scheduler method that returns executor, which ignores error channel or terminates. Overall: what I mean by my comment is the explicit adaptation functions set is still open question to me. And I am raising which one is more fundamental because I see the possible implications to other part of C++ library (e.g. C++17 parallel algorithms).
make_executor_from_scheduler — Weakly Favor
I approve of the simplification. I disapprove of the resulting bifurcation. There will be two async worlds - libraries that deal in executors and libraries that deal in schedulers. The status quo required library authors to consider and support both - now authors will focus on one and ignore the other. Given this change LEWG needs to decide which will survive and remove the other one.
— Weakly Favor
4.1.2. Poll 1
Use one class for each individual trait instead of combined traits classes
(
, etc) in [P0443R14] (Executors).
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
7 | 7 | 7 | 5 | 2 |
4.1.2.1. Outcome
No consensus. We encourage a separate follow-on proposal exploring individual traits versus combined traits classes in general, using [P0443R14] (Executors) as an example to gauge impact.
4.1.2.2. Selected Comments
We’ve been moving towards single traits in general. They are easier to specialize, and are more future-proof.
— Strongly Favor
' implementation is complicated. Separate traits are easier to implement and use in metaprogramming.
sender_traits — Strongly Favor
Combined trait classes are often burdensome as extensive experience with
or especially
numeric_traits has shown.
iterator_traits — Strongly Favor
I feel this is a preferable approach as it makes the traits more extensible and aligns with the precedent set by more recently introduced traits.
— Weakly Favor
I think it’s worth thinking about using one class per trait, but I don’t think this should delay the proposal.
— Neutral
Can live with both
— Neutral
I’m conflicted. I like them grouped when they’re being used for their original intent. It helps when learning about what needs to be defined. If trying to reuse a trait for something else, then it can be unfortunate. That case should probably define a specific trait for its own use.
— Weakly Against
For associated types, current practice is for one trait per concept (
,
iterator_traits ,
allocator_traits ,
incrementable_traits ). This also brings down total number of class template instantiations. There are exceptions (
readable_traits ,
is_invocable , etc.), so I am only mildly opposed.
invocable_result — Weakly Against
This provides the customiser with more ways to get an already complicated thing wrong
— Strongly Against
4.1.3. Poll 2
Remove
from [P0443R14] (Executors).
It may be pursued in a follow-on proposal.
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
8 | 11 | 4 | 7 | 2 |
4.1.3.1. Outcome
Weak consensus in favor.
Remove
from [P0443R14] (Executors).
A separate follow-on proposal is encouraged as a number of people feel it is
important.
4.1.3.2. Selected Comments
No need to tie
to executors, as the discussion is still ongoing and it isn’t a fundamental necessity.
static_thread_pool — Strongly Favor
[P0443R14] conflates too many things. The thread pool is not fundamental to the concept of execution, and may not be the right default thread pool API for us to provide users anyway (a parallel forward progress system thread pool might be a better default).
— Strongly Favor
[P0443R14] does not define a concept for execution contexts like
. We are not ready to define the shape of an execution context - it is purely implementation defined for now.
static_thread_pool — Strongly Favor
is niche but doesn’t look that way, especially if it’s the only execution resource provided in C++23. We would be setting the community up to fail in the future when we standardize
static_thread_pool .
system_executor — Weakly Favor
There needs to be some concrete execution context available at the time that executors/schedulers become available in the standard. However because of the length/complexity of P0443, important sections, such as
, can get lost in discussions. For this reason, I think it would be better to isolate it in its own proposal so that it gets the full attention it requires.
static_thread_pool — Weakly Favor
It’s still unclear to me how
is problematic, but I’m not against it if it builds consensus.
static_thread_pool — Neutral
I don’t care for designs that are all framework, but no concrete implementation.
seems useful in portable code, and it doesn’t seem terribly onerous to specify or implement.
static_thread_pool — Weakly Against
I feel it is important to have an initial thread pool executor available with executors when they are first introduced to C++ as it is a feature high in demand and provides the first standardized execution context, setting the convention for the execution context - executor relationship, so I would prefer the
to remain in [P0443R14].
static_thread_pool — Weakly Against
The
functionality is simple, succinct, mature, and satisfies a very common use case.
static_thread_pool — Strongly Against
4.1.4. Poll 3
Remove
from [P0443R14] (Executors).
It may be pursued in a follow-on proposal.
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
10 | 9 | 4 | 4 | 2 |
4.1.4.1. Outcome
Consensus in favor.
Remove
from [P0443R14] (Executors).
If advocates for
still wish to pursue it, they should bring a
separate proposal which contains detailed motivation and discussion of the
ABI impacts and risks of
.
4.1.4.2. Selected Comments
There are too many open questions about whether wrapping just any executor or more broadly using reference wrappers. It also added a lot of questions where we seem to be defining mechanisms purely to support this type, yet it is not fundamental to the execution concepts [P0443R14] should be focused on. It is important we have such a thing, but it should build on what is in [P0443R14] rather than driving it.
— Strongly Favor
Separating any_executor from [P0443R14] will allow it to make progress faster.
— Weakly Favor
is complicated enough that keeping it in [P0443R14] would slow things down.
any_executor — Weakly Favor
has long complicated many aspects of the design of executors, properties in particular. While I understand and sympathize with the use case, I don’t view this as essential to executors and would be willing to ship a standard without
any_executor . We don’t need a type erasure mechanism for everything in the standard. There are many facilities in the standard library, such as iterators and ranges, which could have a type erasure mechanism, but do not. Additionally, standardizing type erasure facilities almost always leads to ABI issues down the road. Once we ship an
any_executor , it will be much harder to modify and fix problems in both executors and properties down the line.
any_executor — Strongly Favor
Shipping it with executors will lock us into an ABI and I am very VERY much against that.
— Strongly Favor
My main concern is ABI. If we get a proposal that adds a version field or something similar to it so that we can improve
in the future, then I would be fine leaving it in the main paper.
any_executor — Weakly Favor
I think if it’s possible to make the things separated they probably should be split. It allows them to move in parallel without stopping each other. Furthermore, the Executors unified proposal looks too big. If we can make it simpler to read and to understand, let’s do that.
— Weakly Favor
There is enough disagreement around
that it should be a separate proposal.
any_executor — Weakly Favor
The erasure for the concepts are hard to specify and review, and I believe this should be pursued with paper that presents concrete use case (Networking TS).
— Strongly Favor
I’ve always been neutral on whether or not executors should contain a type erasure mechanism from the start, but others were so strongly opinionated in the past that we added it. I’m in favor of whatever builds the most consensus.
— Neutral
I don’t know what type I’m supposed to use for non-generic code if this facility is removed.
— Weakly Against
I believe that the polymorphic wrapper is a major use case for a number of applications and it should go together with the base specification.
— Weakly Against
is a convenient base for implementing polymorphic executors where two domains must intercommunicate. Furthermore, this would impact negatively on the Networking TS as IO objects would be required to know their executor types. This negatively affects: 1. code reuse with coroutines, and 2. compile times.
any_executor — Strongly Against
A polymorphic executor is on the critical path for networking + [P1322R2]. Deferring the choice of target executor until runtime is an extremely common requirement.
— Strongly Against
4.1.5. Poll 4
Remove
and
from [P0443R14] (Executors).
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
12 | 10 | 4 | 2 | 0 |
4.1.5.1. Outcome
Consensus in favor.
We have decided to remove
will be removed from [P0443R14], but if
it is pursued in another proposal,
and
shall be removed.
4.1.5.2. Selected Comments
These methods come with an unavoidable overhead which we should not impose on users. If you need this functionality, it has been demonstrated that you can achieve it using properties. Adding
and
target to
target_type was a mistake that we should not repeat. Removing these methods is consistent with other similar facilities that are in flight (
std :: function and
any_invocable ).
function_ref — Strongly Favor
Including them breaks "don’t pay for what you don’t use" by forcing RTTI to be generated and stored in any_executor even if never called, and it’s possible to replicate the semantics removed here with properties.
— Strongly Favor
The functionality that relies on this in the Networking TS can be re-implemented in another way. The current interface defeats the purpose of polymorphism by asking "what are you?", rather than the pertinent question of "can you fulfill my requirements?"
— Strongly Favor
I believe that
has utility and have used it in production code.
any_executor :: target less so and seems to be the point of contention due to RAII overhead. Given that these removals were coupled in the poll question I have to vote against although I would be weakly in favor of removing
any_executor :: target_type .
any_executor :: target_type — Weakly Against
4.1.6. Poll 5
[P0443R14] (Executors) is sufficiently mature that we should aim to ship it in C++23.
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
10 | 12 | 7 | 10 | 1 |
4.1.6.1. Outcome
Weak consensus in favor. We will continue on our planned course of aiming to ship [P0443R14] (Executors) in C++23, but a notable minority in Library Evolution are not convinced that [P0443R14] (Executors) is sufficiently mature. Library Evolution wants to see more field experience with [P0443R14] (Executors). [P0443R14] (Executors) authors and advocates should take note of this. Focus on demonstrating field experience through implementations and usage, improving introductory material, minimizing the scope, resolving outstanding minor open issues, and developing wording to increase Library Evolution confidence in the maturity of [P0443R14] (Executors).
4.1.6.2. Selected Comments
The executors design that is in [P0443R14] is the result of a long period of hard work and compromise from a large number of authors from various different domains and I feel that it has now settled into a very stable state that well represents the various use cases identified and there has been enough implementation experience that I am confident in the design. I feel that there are still aspects which may need further iteration but a great many alternative approaches have been exhausted in the route to where we are now and I don’t believe that the core design should change significantly.
— Strongly Favor
Executors has made a lot of progress over the years and I believe we are on track to ship it in C++23. Assuming that we adopt [P2235R0] (Disentangling Schedulers and Executors), the proposal becomes a lot simpler, and I think once the dust settles from that and other proposed simplifications we will have a solid core proposal.
— Strongly Favor
While I have some concerns about Executors, and there is a chance it may not be ready, I do not believe at this point we should derail this car from the train.
— Strongly Favor
We should certainly (continue to) aim to ship it in C++23.
— Weakly Favor
The executors design discussion has been going on for a long time. It has matured to the point where I think it’s important to focus our efforts on shipping it. Focusing on making design decisions that move us closer to shipping in the IS is valuable at this point.
— Strongly Favor
Executors (+schedulers, sender, receiver) are basic building blocks of so many library proposals we MUST aim to ship them in C++23 after missing C++20. It hampers the overall evolution of C++.
— Weakly Favor
I think P0443 is mature enough that we should continue with the goal of landing in C++23. There is a risk that we will work on [P0443R14], but not make C++23, and some other features will miss C++23 because of the time spent on P0443. But I think the benefit of getting executors into C++23 is big enough and the chance of success high enough that it is worth taking that risk.
— Weakly Favor
The recent discussions indicate that, while significant tweaks are justified, the basic design is sound, and prioritizing its (cleanup and) adoption is necessary to meaningfully consider other proposals in flight.
— Weakly Favor
Ideally, I would prefer more usage experience.
— Weakly Favor
I think this still has a chance, but it will be tough. I am particularly concerned about getting the wording into a useful state in time for LWG to get through the paper. It is a bit disheartening to think that it’s already "late" into C++23 design when we just released C++20 in February.
— Neutral
Significant aspects of the design seem to be still in flux, and the paper doesn’t report implementation/usage experience for the combined facility (even though parts of it have been implemented in different libraries). This seems less than optimal for something as fundamental as executors.
— Neutral
I feel unable to support moving this proposal forward since I still find it next to impossible to understand what’s going on, despite extensive discussion and leading a review group.
— Weakly Against
I don’t know that the committee fully understands the whole proposal. I don’t know that the authors' implementation experience is sufficiently diverse.
— Weakly Against
There are too many things blocked on executors not to try to ship it as soon as possible. The addition of senders and receivers is essential. The use of properties -- which need for which has never been satisfactorily explained -- smells like an immature element. If properties were replaced with
CPOs would change me to strongly favor.
tag_invoke — Weakly Against
I strongly want executors to make progress towards standardization; however, I am concerned by the number of fundamental changes that have been proposed recently. For example [P2235R0] proposes a design change that completely separates executors / schedulers. There have also been discussions in the last month about whether properties (a large part of [P0443R14]) are the right abstraction. There is also disagreement in SG1 [on whether] algorithms will receive executors or schedulers as arguments. It seems premature to standardize executors/schedulers without knowing what the
algorithms will actually use. There is also very little, if any, practical experience with what is specifically proposed in [P0443R14].
std — Weakly Against
4.2. Other Polls
4.2.1. Poll 6
Send [P2212R1] (Relax Requirements for
) to LWG for C++23,
classified as an improvement of an existing feature ([P0592R4] bucket
2 item).
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
18 | 13 | 3 | 0 | 0 |
4.2.1.1. Outcome
Strong consensus in favor.
4.2.1.2. Selected Comments
This is a very small fix which relaxes an unnecessary requirement to support additional valid use cases.
— Strongly Favor
This is a great step towards stateful clocks that are required for simulation and testing faster-than-real-time.
— Weakly Favor
4.2.2. Poll 7
Send [P2166R1] (Prohibit
and
Construction
from
) to LWG for C++23, classified as an improvement of an
existing feature ([P0592R4] bucket 2 item).
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
15 | 18 | 2 | 2 | 1 |
4.2.2.1. Outcome
Consensus in favor.
4.2.2.2. Selected Comments
This adds a very valuable protection against common errors and makes
more "self-documenting". The counter-argument that this precludes an eventual permission to allow
string_view to be constructed from a single null pointer argument seems entirely unhelpful, since such an extension itself would be a poor and unfortunate direction to take (as has been amply discussed, and as was in fact subject of an overwhelmingly clear straw poll).
string_view — Strongly Favor
There is enough benefit to this proposal in preventing bugs that we ought to do it, even though the same bug at runtime may not be caught.
— Weakly Favor
We’ve discussed this topic many times. We can’t fix all the potential footguns, but this covers a decent set of them, so I’m in favor of it.
— Weakly Favor
This is only a partial solution to the problem of creating a string from a null pointer, and the proposed solution has complications.
— Weakly Against
I was doubting about Weakly Against and Strongly Against. But chose the latter. Yes, this proposal is very easy to implement but it’s doesn’t bring much value to me. It covers very small subset of use-cases. As the paper says it doesn’t help if the
and then we construct
pointer p = nullptr and I understand that we cannot do anything useful here at compile-time. What I mean (and the paper explicitly says that) the previous use-case still requires run-time check. Furthermore, the proposal doesn’t look deeply elaborated. It doesn’t answer the questions what happens if we construct
string ( p ) or
string ( NULL) . With that proposal I am guessing it would cause ambiguity and probably it’s better than run-time failure but still doesn’t look very obvious to the user. I would like to see other design considerations. For example why don’t just mark some templatized constructor as
string ( 0 ) ? I am not saying this is the good solution because it’s just taken from the top of my head. But it seems it can cover more use-cases with
= delete ,
nullptr ,
0 NULL
and potentially others, which looks better to me. Anyway, other possible solutions should be elaborated and described in the paper. Overall, I think that this proposal needs more work to be done. If the solution for broader number of use-cases wouldn’t be found I would not ship this proposal just for the sake ofuse-case. Currently, I would prefer having some run-time checks (e.g. assert) in the debug version of C++ standard library implementations rather then current state of the art of [P2166R1].
nullptr — Strongly Against
4.2.3. Poll 8
Send [P2161R2] (Remove Default Candidate Executor) to LWG for the Networking TS Working Draft, classified as a focus work item ([P0592R4] bucket 1 item).
Strongly Favor | Weakly Favor | Neutral | Weakly Against | Strongly Against |
---|---|---|---|---|
6 | 14 | 2 | 2 | 0 |
4.2.3.1. Outcome
Consensus in favor.
4.2.3.2. Selected Comments
The current default executor,
makes races to completion implicit in the design and should absolutely not be the default.
system_executor — Strongly Favor
This makes it much more difficult to accidentally run afoul of UB when writing networking code. No behavior is lost you just have to opt into the behavior which is always good if the behavior is potentially dangerous.
— Strongly Favor
Executors (in either the Networking TS or in the SG1 incarnation) are meant to provide better control for siting work; making it easy to not exercise such control is not very important and may silently harm performance portability.
— Weakly Favor
Since the executor design and its eventual integration with networking is still in flux, and we do not plan to ship a networking TS v2, forwarding this as a standalone paper at the highest priority seems to be a poor use of limited LWG time. It should be folded into some "integrating executors and networking" paper once the executor design is settled.
— Weakly Against
I think a platform-specific default is useful.
— Weakly Against