13 ms·
C++ coroutines: Initial implementation pushed to master
- g82918 7y agoThis is pretty big news. That is the biggest c++2a feature I want to use.
- beyondCritics 7y agoMe too. It's a lot of fun coming.
- g82918 7y agoI am working on a red-green threading on Linux, what interests you?
- gigatexal 7y agoBut no concepts, no const expr, or use of auto at least according to cppreference
- LessDmesg 7y agoIt'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).
- imron 7y ago> yet instead of fixing anything they just pile up more features in an effort to compete with Rust and Go I used to be a C++ diehard, but modern C++ is why I started learning Rust. If I'm going to have to learn a whole bunch of new idioms and rules, I might as well do it with a language that has the new features and safety built-in, rather than bolted on.
- rumanator 7y ago> I used to be a C++ diehard, but modern C++ is why I started learning Rust. If I'm going to have to learn a whole bunch of new idioms and rules You don't. Just because you bump a version number it doesn't mean you are forced to use all the bells and whistles.
- Rizz 7y agoThat stops working once you're no longer a solo developer, but part of a team, then you need to learn everything any of your fellow developers might use. You might as well focus on learning a new language and having access to new jobs where you don't have to deal with legacy languages.
- rumanator 7y ago> That stops working once you're no longer a solo developer It doesn't. If you have any experience working on C++ projects you will be very aware that deciding which feature is and is not used is the kind of stuff which is defined in the project's coding guidelines docs, along with naming conventions and choice of build system. With C++ you only have to use a feature introduced after C++11 if you decide you really want to use it. Some projects even in this very day still don't use smart pointers or exceptionsor std::array. Some people still do the old C with classes thing. Moreover, the world does not come to an end if you arrive at a project and need to learn a feature provided by a programming language.
- cowsandmilk 7y ago> If you have any experience working on C++ projects you will be very aware that deciding which feature is and is not used is the kind of stuff which is defined in the project's coding guidelines And you will find that you have to learn these features once they are allowed in the guidelines. Some workplaces stick to the old features. Some regularly update with pushes toward use of modern features. When your coding guidelines prefer modern C++, you have to learn it.
- deleted 7y ago[deleted]
- dgellow 7y ago> in an effort to compete with Rust and Go I think that you overestimate how much Go and Rust are used in the wild, and how much of a threat they are to the C++ ecosystem. IMHO C++ is mainly competing with its own past.
- throwaway17_17 7y agoI genuinely believe statements like GP’s are a result of living in a cutting-edge tech bubble, not necessarily SV, but online hype and discussion based reality. Sure several large impactful projects use Go and a few companies are dabbling in using Rust. However, the number of these usages is dwarfed into near statistical irrelevance by the amount of C++ code in active production and usage (it is even more irrelevant if you count programs written in C). That is not to say there is nothing good or beneficial about these languages, devs using them are free to evaluate the features provided and find that they suit their use case and go get to work. But some dev’s pet language, no matter how loudly they scream on Reddit and HN, is not yet threatening C++.
- Darvon 7y agoI can't imagine a real world robotic assembly line in 2020 not using c/c++ indefinitely. Doesn't matter how cool the new language is, what people really want is to not have to rewrite that dependency they're still using from 1998.
- simias 7y agoYou can't fix C++ because the only thing there is to fix is to get rid of all the legacy baggage but doing that would break backwards compatibility (including probably compatibility with C) which means that it's not C++ anymore. "Fixed" C++, per your description, already exists. It's called D. It's called Rust. It's called C#. It's called Go. Meanwhile there appear to be many people who (I must admit much to my puzzlement) seem to still enjoy writing C++ and want to add even more features and paradigms to it. I wish them good luck and I'll be sure to look at the results from afar and see if I can recognize some bits of the C++ I used to write 15 years ago. Oh! I think I saw an "if"!
- blub 7y ago"It's called D. It's called Rust. It's called C#. It's called Go" All of these languages with the exception of D are completely different. It's like saying you fixed a cupboard by replacing it with a sofa. D's the most similar, but it's sadly not exactly a hot language or one where there's jobs available.
- bluejekyll 7y agoWas the cupboard being used as a sofa?
- The_rationalist 7y ago* rid of all the legacy baggage * It keeps being repeated over and over but where can I find such a list? There's almost no misfeature in c++. It's issues are just the fact it's too low level / manual.
- 72deluxe 7y agoHow is it too manual compared to eg C# where I need to implement IDisposable and wrap use of variables in "using" to really ensure something is cleaned up when I want it cleaned up (without risky memory ballooning relying on the GC)? C++ destructors to clean up your resources are really neat. And deterministic - you know when stuff is going to get cleaned up. Or was it some other "manual" feature that's too much of a burden? Honestly curious.
- 72deluxe 7y agoIn 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!
- jefftk 7y agoI mostly agree with you, but operating systems and web servers are generally written in C and not C++. For example Linux, (the vast majority of) GNU, Apache, and Nginx are all C. (Though I expect your parent has similarly negative views on C?)
- 72deluxe 7y agoYou are correct, thanks. My comment comes across as very irritated, but it's the same argument that will continue to the end of time I guess - "this tried, tested and widely used language is broken because it is not language $x and because it lacks this edge-case invented usage scenario even though it works adequately for 99.9% of all other scenarios as demonstrated by decades of use". It's wearying. Sure, C++ is complicated but so is English! I thought nginx was C++? I also thought large portions of Windows are C++? Everybody loves COM!
- bouncycastle 7y ago> an airplane engine from Rolls-Royce RR makes excellent aircraft engines, for both Boeing and Airbus https://en.wikipedia.org/wiki/Rolls-Royce_Trent https://en.wikipedia.org/wiki/Rolls-Royce_Trent
- gerikson 7y agoIn addition, Rolls-Royce cars are made by BMW now, who also make quite good engines.
- bouncycastle 7y agoCorrect. RR doesn't make cars anymore, it's only just a badge. Also, RR is dominating the marine propulsion sector, these engines are some of the largest in the world!
- gerikson 7y agoThis I did not know, interesting!
- endorphone 7y ago"yet instead of fixing anything they just pile up more features in an effort to compete with Rust and Go" Alternately they're iteratively evolving the language as each generation of features are fleshed out? They've been doing this for several decades now. It's their job. And for those people using C++ tooling, or working on C++ projects: Cool, new stuff to ease some edge conditions.
- pjmlp 7y agoAs much as I like Rust, progress usually comes in progressive changes, not with big bangs. Modern C++ is already a large improvement over C, which was already a 19th century carriage, when everyone was moving into steam cars.
- tsimionescu 7y agoUnfortunately, modern C++ still includes (the vast majority of) C, both in theory and in practice in many code bases around the world.
- pjmlp 7y agoIndeed, and it is its Achilles tendon, once its Trojan horse for adoption, nowadays the source of security headaches. However, I don't see many companies throwing away their IDEs, game engines, build systems just like that. It is easier to migrate those teams to static analysis tooling, than throwing it all away and start from scratch in another ecosystem. Hence why both Microsoft and Google are still two major contributors to ISO C++, in spite of being in the process of adopting Rust.
- stjohnswarts 7y agoCan you point out where Google and Microsoft are moving to Rust because I've seen none of that.
- steveklabnik 7y ago“Moving to rust” is too strong; they are both adopting Rust for real, production use cases. I’ll give you one example of each: Google is using Rust in ChromeOS, at the virtualization later, and Microsoft is using ripgrep to power the search for VS: Code. There’s more than just that but those are the two easiest things to point to.
- jcelerier 7y ago> https://gcc.gnu.org/projects/cxx-status.html https://gcc.gnu.org/projects/cxx-status.html seems more up to date than cppreference
- gigatexal 7y agoNo I meant that from cppreference using coroutines means you can’t use the features I mentioned not that those features don’t exist in c++20
- nemetroid 7y agoThe concepts part I'm not sure about, but the other parts don't look so bad. According to cppreference.com[0]: > Coroutines cannot use variadic arguments, plain return statements, or placeholder return types (auto or Concept). > variadic arguments For the purposes of creating variadic functions, variadic templates are the preferred solution, since variadic arguments have a number of drawbacks (e.g. unavoidable type promotions). > plain return statements This is the definition of C++ coroutines, more or less. > placeholder return types (auto or Concept) Note that this isn't the typical use of auto (i.e. inferring the type from the right hand side of an assignment), but about return type deduction. From a quick read, it looks like there are multiple, equally valid kind of coroutines (e.g. lazy<int> vs generator<int>) which cannot be deduced from the body of the coroutine. It could be argued that lazy<auto> should work, but I would guess it clashes with all the already existing complexity of template deduction. I agree that this looks like a wart but not a horrible one. I'm not sure about the concept part, would have to learn more about concepts to comment. > Constexpr functions, constructors, destructors, and the main function cannot be coroutines. > Constexpr functions Constexpr functions are functions whose value can be decided at compile time. Coroutines can call constexpr functions, they just can't be one. I guess it could be useful to determine the full output sequence of a coroutine at compile time. Maybe it could be added in a future language version, if it's worth the added complexity. > constructors, destructors, and the main function cannot be coroutines I guess this is just formalism, having those things as coroutines doesn't make logical sense. 0: https://en.cppreference.com/w/cpp/language/coroutines https://en.cppreference.com/w/cpp/language/coroutines
- gigatexal 7y agoThanks for the itemized reply. Your points make sense
- ncmncm 7y agoC++ is getting more fun to use, every cycle. C++11 was a huge step up with lambdas, move semantics, atomics, threads, constexpr functions, loops over containers, and loads more. C++14 added generic lambdas and lifted lots of arbitrary restrictions, making everything smoother. C++17 added destructuring, template argument deduction from constructor arguments, and constexpr if. C++20 brings concepts, ranges, modules, coroutines, and automatic comparison opetators. Each time, more kinds of programming are made natural and easy to write, and more old workarounds become unnecessary. We hardly ever need to write out constructors, copy assignments, or destructors anymore; or even, with '20, comparison operators. Template metaprogramming is mostly unneeded now.
- tus88 7y agoThere have been library implementations of this for years. And they are a far cry from true lwt aka golang.
- anonymoushn 7y agoGoroutines are not copyable so they're not really a substitute for byuu/co
- tomcam 7y agoI think my mind is about to be blown. What does copyable mean when it comes to coroutines?
- anonymoushn 7y agoA description of one thing you can do with this is at https://github.com/moonjit/moonjit/issues/84 https://github.com/moonjit/moonjit/issues/84 It's not a common feature. Usually it's present in a language that has "continuations" and the api is something dreadful like call/cc. But you can use it in Lua with the above mentioned patch, and you can use it in byuu/co with memcpy.
- simias 7y agoI object to the use of "dreadful" for call/cc, it's just a different paradigm that requires a different way of thinking but it's not a bad thing per-se. It's not like goto or setjmp which are fundamentally unsound constructs that completely break the flow of the program.
- anonymoushn 7y agoWhen designing these primitives, I think there are a few considerations: When creating a new execution context, which one should begin executing, and which one should be bound to a local variable in the executing one? Should there be any primitive that switches to an already-existing execution context without creating a copy of it? How many primitives should there be? call/cc answers: "The new execution context should begin executing and the old one should be bound to a local variable, no, one" As a person who occasionally explains these things to people who have never been exposed to them, I strongly prefer: "The old execution context should continue executing and the new one should be bound to a local variable, yes, as many as we need to produce the preceding answers" I think without trying too hard you can get the number of primitives in the latter case down to three, "create", "copy", and "switch." If you wanted to bug your users you could get it down to two.
- ncmncm 7y agoIn other news, Iain doesn't have zstd yet :-).
- ezoe 7y agoDon'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.
- MaxBarraclough 7y ago> In my opinion, these features should better be implemented by powerful generic static reflections rather than a dedicated special syntax just for this. Boost has had a coroutines library for some years now. What do you make of their approach?
- gpderetta 7y agoC++ coroutines are pretty much the same as stackless generators/async from other languages (python, JS, C#). They have nothing to do with range for. They are not stackful coroutines, like thise from lua for example, but multiple implementations of thise are available as a library. There still a chance they might make it to the standard library.
- nly 7y agoIt's not just syntax sugar, since the compiler still does the hard work of capturing local variables in to a (stackless) activation record
- 7y ago
- stevefan1999 7y agoAh, 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 7y agoDo 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 7y agoThe 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
- tsimionescu 7y agoStill, the fastest C++ framework there is slower than than both the fastest Go-based fwk and the fastest Java-based one.
- dnpp123 7y agoYes 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.
- dathinab 7y agoHonestly 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.)
- quietbritishjim 7y agoA typical solution is to use shared pointers, and just try to take care to avoid ownership cycles. It's certainly common when using ASIO callbacks, which are a bit like coroutines, especially if they're methods of a class that represents the overall "function". I don't know much about C++2a coroutines but maybe a similar strategy could be used for them too. In a sense, reference counting isn't far off being a basic form of GC. In fact CPython uses reference counting and only uses anything else for detecting cycles.
- gumby 7y agoReference counting is a form of garbage collection. I don’t like the trade offs for many applications (problems with cycles and runtime overhead) but when you can’t use a transporting collector it’s often better than mark/sweep
- gpderetta 7y agoAsio enforces exactly once semantics for callbacks, so if you are careful you can thread your state through your callbacks [1] in a linear way and avoid reference counting. It is not always worth the effort though, but coroutines should make it trivial. [1] last time I checked ASIO didn't support move only callbacks so it was ackward to implement. Things might have changed since.
- asveikau 7y agoI rather like c++ closures in that they are pretty explicit about how capture works. Given the other concepts in the language it is absolutely necessary to consider how closure capture works with the copy constructor, for example. I would contrast it with objc blocks, where capture is pretty implicit and sometimes feel ambiguous. But I think that copy constructor is the root of a lot of evil performance penalty in c++. In the old days it was especially easy to over-allocate with vector or string. Move semantics fixed some of this. But passing around closures without a lot of care is also a consequence. An "easy" solution, to capture a shared_ptr, is not without its costs.
- stjohnswarts 7y agooooo nice.
- ehvatum 7y agoSorry, 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?