Some notes:<p>- C++20 coroutines are <i>stackless</i>, meaning that multiple coroutines will share a single OS thread stack. This is non-obvious when you first look in to them them because coroutines look just like functions. The compiler does all the work of ensuring your local variables are captured and allocated as part of the coroutine yield context, but these yield contexts are <i>not stack frames</i>. Every coroutine you invoke from a coroutine has its own context that can outlive the caller.<p>- C++20 coroutine functions are just ordinary functions, and can be called from C code. In fact, coroutine contexts can be cast to and from void* to enable their use from C.<p>- There's currently no generic utility in the C++20 standard library for using C++20 coroutines to defer work. std::future<> only works on threaded code, and you can't really use std::function<>. See Lewis Bakers 'task' class for a usable mechanism <a href="https://github.com/lewissbaker/cppcoro#taskt" rel="nofollow">https://github.com/lewissbaker/cppcoro#taskt</a>
Part of this is that I’m tired, but it blows my mind how difficult C++ coroutines are as someone who considers themselves decent at C++ (although maybe I’m not) and uses coroutines in other languages. The amount of code needed to do almost nothing is extraordinary, and putting it all together doesn’t seem like you would often get on your first try. I get that new keywords basically can’t be added, but man, that’s painful.
I've used C++ coroutines (with io_uring). They are really useful in this case and allows one to write code like one would with the simple blocking API. And from what I've read they are better than Rusts coroutines for this use case (and for the yield use case they aren't good).<p>It adds an additional foot-gun w.r.t. to e.g. by-reference parameters to functions and their lifetime. The function parameter might not be alive anymore after a "co_await" and it doesn't require any capture (like lambda) or has any hint about this being the case.<p>Then, the tooling isn't there yet (other than the missing standard library). Gdb doesn't show correct lines and can't print local variables when in coroutines. If there is a deadlock one can't see the suspended coroutine (and its call stack) holding the lock, etc.. Back to printf debugging...
Seems like once again we are stuck with an overly complex and un-ergonomic design that is going to burden every single C++ programmer for a decade, until someone gets fed up and fixes it. Just like chrono, just like random, just like std::string, all of std::algorithm, etc. God damn it.
> C++20 coroutines are implemented as a nice little nugget buried underneath heaps of garbage that you have to wade through to access the nice part. Frankly, I was disappointed by the design, because other recent language changes were more tastefully done, but alas not coroutines. Further obfuscating coroutines is the fact that the C++ standard library doesn’t actually supply the heap of garbage you need to access coroutines, so you actually have to roll your own garbage and then wade through it.<p>Well, that sounds like more fun than a tax increase.
What I find interesting about coroutines is that they are relatively trivially achieved in hand-coded assembly using `jmp` and being careful about registers in a way that makes sense. `jmp`ing around is a pretty normal way to code in assembly. In a sophisticated environment they become a beast. It surprises me that we actually do lose something meaningful when abstracting to higher level languages.
Keep in mind that these is a really basic building block where you can bring your own runtime and hook coroutines into it, not something that is at all usable out of the box. This is exacerbated by the fact that the C++ standard library is still lacking support for non-blocking futures/promises and queued thread pools to run them.<p>To see how it can be used for actual asynchronous operations on a thread pool, take a look at asyncly, which I co-authored:<p><a href="https://github.com/LogMeIn/asyncly/blob/master/Test/Unit/future/CoroutineTest.cpp" rel="nofollow">https://github.com/LogMeIn/asyncly/blob/master/Test/Unit/fut...</a>
i used this : <a href="https://blog.panicsoftware.com/coroutines-introduction/" rel="nofollow">https://blog.panicsoftware.com/coroutines-introduction/</a> a while back. maybe someone else might find it useful too...
From the existing explanations, I’ve deduced that coroutines are a form of continuation based coopetative multitasking. Is it possible to “restart” the sequence, and how would this be done?
As a developer, when you decide to use bleeding edge C++?? extensions keep in mind that when you do so you're making it much, much harder to run any of your code on a distro more than 4 years old. Is it worth it?
Note that the author (in addition to being a great professor) is responsible for one of my favorite papers: <a href="https://news.ycombinator.com/item?id=11098655" rel="nofollow">https://news.ycombinator.com/item?id=11098655</a>
I'm a bit confused by all of this.
The idea of coroutines existed since the 60's. Then we came up with OOP that tries to combine function + data. And now we abolished this, are back at only functions and are now solving the 'state capture' problem for functions again with: Coroutines?
How does the history of programming paradigms/patterns make any sense? :)<p>Good article though.
void main() does not exactly inspire confidence.<p><a href="https://stackoverflow.com/questions/636829/difference-between-void-main-and-int-main-in-c-c" rel="nofollow">https://stackoverflow.com/questions/636829/difference-betwee...</a>