
C++ Core Coroutines Proposal [pdf] - anqurvanillapy
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1063r0.pdf
======
pcwalton
It seems that the main issue that the authors of this proposal have with the
current coroutines proposal in the committee is that that proposal effectively
requires allocation for all coroutines, while offering promises that the
optimizer will be able to avoid the allocation in common cases. This competing
proposal makes allocation opt-in for various reasons, not the least of which
is skepticism about how well the optimization will perform. (See "Implicit
allocation violates the zero-overhead principle" in this document [1]).

[1]: [http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2018/p097...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2018/p0973r0.pdf)

~~~
RcouF1uZ4gsC
[http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2018/p098...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2018/p0981r0.html)

The people that actually implement coroutines in the compilers actually think
that eliding the allocation is very doable.

~~~
pcwalton
Richard Smith, quoted in the document I linked as saying "I do not have any
confidence this optimization would ever become reliable in the way that, say,
certain forms of NRVO are," is the code owner of the clang frontend.

~~~
simias
It's also true that relying on the compiler to optimize some stuff away
(instead of making the overhead explicitly opt-in) is not very C++-ish in
nature.

~~~
Chabs
I'd like to introduce you to the wonderful world of templates.

~~~
bergesenha
Do you have any examples of templates incurring a runtime cost at -O0 compared
to a “no templates” approach?

~~~
Chabs
Expression templates (ala boost::spirit) definitely come to mind. The
callstack in a -O0 build can get very, very deep.

Heck just using std::numeric_limits<int>::min() will incur a function call in
-O0, but nobody cares since it gets optimized in -O1 and up. The same thing
applies more and more as you invoke templates from templates, but, again,
nobody cares since we are confident it'll get optimized/inlined easily.

It's not nearly as prevalent in modern code since constexpr static variables
are now a thing, but relying on these optimizations has historically been
super important.

------
kristiandupont
It seems there's a weird fetish in C++ land where non-letter characters seem
more "pure" than words. I remember suffering from it myself, implementing
atrocities like a subtraction opeartor on a path class which would give you
the relative path between two paths. It made me feel very clever but I feel
sorry for anyone who would have to look at my code now and try to figure out
what the hell was going on.

~~~
pcwalton
It's because defining "customization points" as operators make it easier to
write templates, essentially. See "C++ doesn’t know how to do customization
points that aren’t operators":
[https://quuxplusone.github.io/blog/2018/08/23/customization-...](https://quuxplusone.github.io/blog/2018/08/23/customization-
point-or-named-function-pick-one/)

This is one of the downsides of not having typeclasses that is often forgotten
about.

~~~
aaaaaaaaaab
Wouldn’t uniform call syntax (like in D) solve most of the issues outlined
above? I.e. it always boils down to “primitive types can’t have methods”; but
uniform call syntax would let us call any function like a method on its first
argument...

~~~
pcwalton
Or just allow methods to be defined on primitive types, like Rust.

~~~
aaaaaaaaaab
Uniform call syntax is a superset of that, since you can’t have virtual
methods on primitive types.

------
cjhanks
The rapid change in C++ syntax may destabilize it.

For example; `auto OpenFile(const string& filename) using
future_coroutine<File> [filename]`. Okay, I get it. Or the operator `[<-]`.

But as the idioms find their way into production code - an entire important
segment of the C++ developer base is going to no longer be capable of reading
the language. And that might be worse than not having features.

~~~
hfdgiutdryg
I spent a decade watching C++ painfully slowly add more advanced template
support and... well, that's about it. After a million iterations of "for
(mylisttype::const_iterator i ..." they finally added ranged for loops.

The rate of change seems to be increasing. This is initially a bit shocking
until I remember that every single job I had was like using a completely
different language because, even ten years ago, every shop used a different
subset of C++ and STL!

Add all you want to the language, it's all going to devolve into code-review
infighting the same way it did in 2008.

~~~
gpderetta
> I spent a decade watching C++ painfully slowly add more advanced template
> support and... well, that's about it. After a million iterations of "for
> (mylisttype::const_iterator i ..." they finally added ranged for loops.

C++ was first standardized in '98\. Nothing happened for more 10 year (in
particular no new advanced template support) unless you count the very minor
bug fixes in C++03. The next revision, C++11, added ranged for loops.

~~~
hfdgiutdryg
Compilers don't strictly adhere to standards, and I'm far more concerned with
things like whether my compiler crashes, how godawful the error messages are,
and whether the bundled STL even functions reliably.

------
quickben
[<-] "Our proposed spelling is intended to suggest unwrapping"

I'd argue co_unwrap() has spelling that suggests unwrapping.

------
dmoreno
I still have to read it through, but why does it require new syntax and not
just new standard library additions like boost::coroutine?

I just fell in love with boost::fiber so i hope there will be also something
like it in the future std.

~~~
mattbierner
This could be completely off-base but:

\- Clarity and establishing convention. Boost coroutine2 uses a lot of
boostyness to make using coroutines in c++ less painful, but they still
require boilerplate and can be quite difficult to write. Understanding code
that uses coroutine2 also requires understanding how the coroutine2 library
works and how it uses normal c++ syntax in unique ways.

Having a dedicated operator like [<-] arguably produces more familiar looking
and clearer user code. (Take a look at the generator example in the appendix
of this proposal; the implementation of the 'generator' type is horrific but
the 'Traverse' function is pretty easy to read.)

\- Generalization. Boost::coroutine2 targets coroutines. This proposal tries
to generalize aspects of the coroutines proposal such as the unwrap operator
[<-] to support use cases like linear monads.

------
beojan
This doesn't seem to be a coroutines proposal so much as an attempt to sneak
(Haskell's) `do` notation into C++.

Which I applaud, it's a brilliant feature.

------
0xFFC
I don't understand the point of co_*. Why should you have something as ugly as
this? Just use std::coroutine?

~~~
palotasb
They are supposed to be keywords like _return_ or _throw_. Those cannot be
namespaced either.

------
kbwt
And yet this proposal still doesn't let you implement zero-overhead objects-
as-coroutines. I'd like to be able to create a coroutine that initializes some
state ("constructor"), yields back to the caller, and lets you call alternate
re-entry points ("member functions") that manipulate the state and yield back,
or the final entry point that cleans up the state ("destructor"). If the
initialization fails for whatever reason, the yield will simply be skipped.
Crucially, I want to be able to do all of this without indirect jumps other
than returns.

~~~
AndyKelley
Serious question, what's the difference between this and a class?

~~~
BeeOnRope
I guess when you call an entry point the second time it restores the existing
context at the point of the previous yield. So you have mix of shared state
(class members) and local state between the various entry point. Just a guess
though.

~~~
AndyKelley
If the local state was accessed across a suspend point that would be undefined
behavior. So it would have to be spilled into the coroutine frame. So it would
be the same as a class.

------
anqurvanillapy
Bikeshedding alert: If a linear monad use case is considered and a do-
notation-like syntax is proposed, why isn’t a left-bind =<< operator
introduced by nature.

