Hacker News new | ask | show | jobs
by i-use-nixos-btw 1041 days ago
It is due a bit of proof reading. There are some readability issues.

That being said, it is a great article. C++ and coroutines is a story that has been going on for a long time, and the result surprised me. In a bad way.

One bit me right from the start. I copied out an example and it crashed, and it turned out (after hours of searching, reading - the compiler and sanitisers sure weren’t any help) that the problem was that I’d inadvertently made a parameter const& (force of habit) and bound a temporary to it.

My answer to this is simply that I choose not to use coroutines. If I can’t force a compilation failure when I do something dumb, that spooks me.

For a feature released in 2020 it has far too many footguns. Ranges was similar when it came to lifetime footguns. It’s just something that makes it hard to take seriously the claims that it is legacy code that is the reason C++ has a bad rap for safety. Coroutines and ranges are modern features that can shoot your foot off if you don’t know the implementation, which is kind of contrary to the point of making a friendly wrapper over it all.

1 comments

The compiler won't stop you storing a pointer to a local variable and dereferencing it later, either. That's just the nature of programming without managed memory. Calling a coroutine is essentially the same as temporarily "returning" from the current stack frame, so all of the usual practices around taking pointers apply.

I agree with your conclusion of not using C++ coroutines, though. It seems like the design falls somewhere in the "worst of both worlds". I would rather either use a library that implements coroutines with the minimal amount of C and inline assembly if performance is critical, or some higher level abstraction that works well with all other language features.

Having seen a number of footguns with references and lambda captures as well where the compiler won't warn/catch I don't think it's unique to coroutines.

We were using coroutines about ~12 years ago in embedded contexts, this was with Lua which has very good support and being a managed language avoids all the footguns here while still allowing very fast interop with native code(at least in the case of LuaJIT).

I hate to drag Rust into every C/C++ conversation but this is one area where the language really keeps you within the guardrails. Callbacks are hard to use correctly in Rust, less because of the language and more just do to the messy lifecycle aspect of them. You can side-step that with shared_ptr/Arc but then you're stepping into memory leak territory when you have a circular reference(and the atomic ref counting isn't cheap either).

That is why no sane person should use C or C++ without static analysis, at very least on the CI/CD pipeline, lint wasn't created in 1979, only because Stephen Johnson was bored at Bell Labs.
In most languages I'm familiar with, static analysis is something the compiler does at every build. It's not something left to a separate CI/CD step. Code that isn't statically sound shouldn't be hitting the repo in a way that it gets to the CI/CD step.

C++ has always been a bit of an outlier to me for that reason.

Yeah, though that’s also kind of my point. You know and I know (having learned the hard way) that the mechanism involves storing parameters and intermediate values in an object that is referred to later. It’s obvious now I know, but the design hides that from the user - they aren’t supposed to care about that. However, the footguns are still present. There should have been language features to prevent temporaries binding to const& for coroutines, but (according to a friend) the language doesn’t distinguish coroutines and subroutines at that level (… or something?)

Same problem with ranges. The footguns are remnants of abstracting something complex with a friendly interface and failing to secure it. It’s great for people who know the implementation, and it’s obvious where memory issues appear - but if you don’t know the implementation then you end up with holes in your feet.

Many other things extend lifetime of const& in C++ or else operator overloading wouldn't work, so it can be confusing.