
C++ coroutines: Initial implementation pushed to master - matt_d
https://gcc.gnu.org/ml/gcc-patches/2020-01/msg01096.html
======
dathinab
Honestly even with RAII memory management in C++ can be hard, especially with
all lambda/closures. I can totally see this becoming a even bigger mess if
combined with corotines.

Most languages which have anything like corotines/async/await avoid this
problem by using a GC. Rust kinda is will equipted for this with it's borrow
checker (but it's hard for the compiler team to get completely right). But I
don't see C++ to be suitable for many coming/common programming patterns with
them. It is just way to easy to mess up memory management in the edge cases
(like e.g. early cancelation etc.)

~~~
jandrewrogers
As a counterpoint, I've been ubiquitously using coroutines in C++ as the
primary concurrent task scheduling mechanism in database engines for around a
decade. It has always been dead simple and mostly straightforward, resource
leaks were never an issue, though details vary with coroutine implementation.

Since C++11, memory management has been remarkably easy to get right the first
time in complex systems. It isn't just RAII, there are many other mechanics
that enable resources to be automagically managed optimally from the
perspective of the developer. In my experience across millions of lines of
code, resources don't leak ever at this level of abstraction (pre-C++11 is a
different story).

I am perennially baffled by what other people are doing with modern C++ that
resource leaks are chronic problem. I get the impression there are a large
number of C++ programmers that don't grok basic resource management in C++11
(it really isn't that hard) and blame the language when resource management
issues occur.

~~~
hellofunk
Well, just write a simple C++11 lambda that uses a reference capture, and
store that lambda somewhere and watch your app crash when it that lambda runs
after the referenced object is gone. Even if you stick with writing no "new"
or "delete" in your code, just as good modern C++ encourages, this simple
problem will always be there, and it doesn't just affect lambdas, though
that's the sneakiest place it often happens.

Of course you can avoid these problems very easily, but you have to be bitten
by them first to know how easy they are to write.

~~~
Gene_Parmesan
Excuse this ignorance from C# land, but how does one get by in C++ without
ever writing "new"?

~~~
kitd
'new' allocates an object on the heap, where it is prone to being leaked.

Direct allocation on the stack (and maybe moving to the caller function if
needed) keeps everything local and ensures destructors are always called when
the stack unwinds.

~~~
hellofunk
This isn't really the right concept. Lots of objects must be on the heap, as
the stack cannot contain them. The question isn't to avoid putting objects on
the heap, it's to avoid the use of "new" to put them on the heap.

Modern C++ encourages avoiding manually using "new" and relying on smart
pointers for that, as they will automatically call "delete" and avoid a large
class of memory leaks from heap usage.

Note that member objects are often on the heap without using any smart
pointers or use of "new" simply because they inherit the memory area from
their enclosing object, and I've see many inexperienced C++ devs manually
allocate memory for these objects unnecessarily.

~~~
kitd
Thanks. Your answer captures the nuances much better than mine. I was
concentrating simplistically on the difference between heap and stack
allocation, but that misses a lot of the common usage & idioms.

------
ezoe
Don't let its name fool you. C++ coroutines is nothing about the coroutines
you imagine from other languages.

C++ coroutines, defined by C++20 standard is nothing but a syntax sugar. It
consists of three keywards, co_await, co_yeild and co_return. The functions
which use these keywords are said to be a coroutine and it's code will be
transformed such that some specific member functions of the user-defined type
will be called.

And that's everything. It's just a syntax sugar like range-based for.
Actually, it's less than the range-based for because there is no standard
library support for it.

If you wrote a class that does, say, lightweight user-mode threading according
to the C++ coroutine's syntax sugar expect, it become coroutine in the sense
of most other programming languages. It can also support generators and other
idioms if YOU or SOMEBODY wrote a library for it. Good luck with that. Because
even the C++ SC's experts couldn't design and agree upon a good such standard
library until the deadline of C++20.

In my opinion, these features should better be implemented by powerful generic
static reflections rather than a dedicated special syntax just for this.

~~~
nly
It's not just syntax sugar, since the compiler still does the hard work of
capturing local variables in to a (stackless) activation record

~~~
gpderetta
At the end of the day, everything is syntactic sugar over machine code.
Doesn't means it is a bad thing though.

------
g82918
This is pretty big news. That is the biggest c++2a feature I want to use.

~~~
gigatexal
But no concepts, no const expr, or use of auto at least according to
cppreference

~~~
LessDmesg
It's no wonder. C++ is deeply and irreparably broken, yet instead of fixing
anything they just pile up more features in an effort to compete with Rust and
Go. Modern C++ is like a 19th century horse carriage with a big subwoofer (but
you have to bring a bunch of 9V batteries), huge hot-rod wheels (but no
amortization so don't even think about going above 20 kmh) and an airplane
engine from Rolls-Royce (which is there for the sake of heating only).

~~~
72deluxe
In what way is C++ "deeply" broken? I seem to be using it daily with no
problem, as does the rest of the world. I manage to use applications and
operating systems where vast portions of it are written in C++ without
problems - what problems are you having? Honestly, it's dead easy to criticise
but you must be using the product of another language if you feel so strongly
about this...?

Tell me, which browser and operating system are you using to write this
comment? It must be one written in something other than C++, right? Your
browser isn't using WebKit or Blink by any chance is it??

Let's hope the web server or network appliances used to transfer the data to
you are not using software written using this "deeply broken" language!

~~~
yati
I also use C++ everyday, and find it quite powerful, but I also feel that it
is ill designed. The other day I had to work with code that involved a public
member function that returns a private type. You can only bind to the return
value of this function with auto (because the type is private), but can
otherwise do anything with the object. Why this is allowed is beyond me.

You're right that much of the software we use is written in C++, for good
reasons, but asking people to "use a product of another language" just because
they are critical (in a not so nice way, admitted) of it is going a bit too
far. It's like asking someone to move to a different country because they
think their system is "broken beyond repair".

~~~
shortoncash
Your design above with the private type being returned could possibly be
useful. Perhaps outsiders to the class will be prevented from instantiating
the nested-type without using the class itself to generate the nested type.
This could be contextually useful and certain (interface) functionality could
be grouped in a manner that is more convenient to use than by calling methods
on the original class.

I like that C++ allows us to express this situation, even if it's a bit of an
unusual design pattern.

~~~
yati
You can prevent instantiation of the nested type already by using private
ctors and friending the wrapper class from this type, while keeping the class
itself public. That is a much cleaner expression of intent. I believe that if
a class is usable via its interface, it is public any way (in that you will
need to go and change all uses of this object should you decide to change the
nested type's API, whether it is declared private or not).

And also note that binding to the object at all has been possible only after
C++11, while this "feature" works with earlier standards. That rules out the
possibility of this being designed into the language with the express goal of
achieving what you say (it doesn't matter, but just pointing out).

~~~
gpderetta
Visibiliy has always been sabout naming thing. You were always able to bind
private types to template arguments (otherwise you would never been able to
create an std::vector<PrivateType> or pass MyPrivateContainer to an std
algorithm. What's new in C++11 is the ability to also bind locals, but that no
more powerful than what you could do before (via a CPS transform).

------
stevefan1999
Ah, I loved coroutines. Combining this with Boost.ASIO and Boost.Beast, you
can make a high-performance HTTP server/client in C++ quickly while defeating
the competitors several margins far away.

Sadly, coroutine TS in Boost.ASIO is still a preview feature, and I've met a
lot of quirks that stopped me forwarding from using it, for example, sockets
have to be moved even inside a lambda, that can clearly optimized out by
referencing, and I had some frustration of this.

~~~
dnpp123
Do you have any benchmark to back this assertion by any chance ?

The only benchmark I know of is
[https://www.techempower.com/benchmarks/](https://www.techempower.com/benchmarks/)
which is really poorly done but it's better than nothing. Rust seems to
sometimes come first and C++ framework are close (and not by several margins).

~~~
ploxiln
The benchmarks leader "actix-web" was not really regular/typical rust, and
conflict with the "community" caused it to implode. see
[https://github.com/actix/actix-web/](https://github.com/actix/actix-web/) and
[https://news.ycombinator.com/item?id=22075076](https://news.ycombinator.com/item?id=22075076)

~~~
dnpp123
Yes this is why I said the benchmark is poorly written. It encourages
frameworks to do such thing.

Even if you look at the code of hyper for the benchmark, it does some ugly
things not recommended in production. I'm not blaming actix/hyper's authors,
I'm blaming the benchmark author encouraging (not voluntarily) such practice.

However the benchmark is enough to see that C++ is not faster by several
margins, hence my curiosity about benchmarks proving otherwise.

------
ehvatum
Sorry, I just got back from a long vacation. For users still on C-front, what
benefits are to be had by moving to a compiler supporting std lib coroutines?

------
stjohnswarts
oooo nice.

------
ncmncm
In other news, Iain doesn't have zstd yet :-).

------
tus88
There have been library implementations of this for years. And they are a far
cry from true lwt aka golang.

~~~
halayli
Is that so? Please elaborate

~~~
civicsquid
It looks like Facebook's `folly` library had an implementation of coroutines
available in their experimental directory since mid-2018. There was still some
evolution going on after it was pushed though (and it seems like there still
is today).

Not sure if that helps the argument that this has been around for "years"
(since it's still in the experimental directory), but I guess there were some
libraries trying to accomplish this.

[https://github.com/facebook/folly/tree/master/folly/experime...](https://github.com/facebook/folly/tree/master/folly/experimental/coro)

~~~
pjmlp
The only implementation that I would consider around of years, were the C++/CX
extensions, and even those aren't 100% like ISO C++ ones ended up looking
like, although Microsoft was a big contributor to its design.

