[HN Gopher] C++20 coroutines: "The bug is in the C++ standard, n...
       ___________________________________________________________________
        
       C++20 coroutines: "The bug is in the C++ standard, not GCC."
        
       Author : flykespice
       Score  : 114 points
       Date   : 2022-10-04 18:14 UTC (4 hours ago)
        
 (HTM) web link (gcc.gnu.org)
 (TXT) w3m dump (gcc.gnu.org)
        
       | somerando7 wrote:
       | You have to use something similar to
       | https://github.com/facebook/folly/tree/main/folly/experiment...
       | to solve this problem.
       | 
       | It's a nasty bug that everyone encounters when first working with
       | coroutines. (Similarly everyone will encounter references that
       | don't live until you co_await the task).
        
         | grogers wrote:
         | Alternatively, you can pass the things you would have captured
         | instead as arguments to the lambda (by value!) and they are
         | valid for the duration of the coroutine. So you can do a lambda
         | returning a coroutine lambda like                 task<Foo> t =
         | [foo]() {         return [](auto f) -> task<Foo> {
         | co_await something();           co_return f;         }(foo);
         | }();
        
         | boundchecked wrote:
         | C++20 coroutines demonstrated one side of committee-led modern
         | C++ that left an impression of it is ultimately designed-by and
         | -for library writers; instead of being suggested third-party
         | library or "wait for C++23" for better experience, I'd love to
         | see these related machinery released the same time in the
         | standard library.
        
       | rwmj wrote:
       | This is from Avi Kivity who added KVM (virt) support to the Linux
       | kernel.
        
       | scatters wrote:
       | This is fixed in C++23 by adding explicit object parameters to
       | the member function (and lambda) syntax:
       | [x](this auto) -> future<T> {             co_await something();
       | co_return x;         }
       | 
       | The lambda capture is copied into the coroutine frame on launch,
       | meaning that it won't dangle.
        
         | jmt_ wrote:
         | I would have never recognized this syntax as modern day C++
         | without being told. The language has evolved so much in the
         | last 30+ years that I don't know how anyone is able to keep up
         | unless they've been doing it for decades. As a junior dev, C++
         | scares the hell out of me - I'd rather wrestle with C, footguns
         | and all, than wrestle with the foot-semiautomatic-rifles C++
         | provides.
        
         | sitzkrieg wrote:
         | this looks so far and away from C++ of ye old its kinda funny.
         | you could pass that as some new language
        
           | MathMonkeyMan wrote:
           | future<c++>
        
           | jcelerier wrote:
           | > you could pass that as some new language
           | 
           | ...why would you think that a new standard isn't a new
           | language?
        
             | ijlx wrote:
             | I mean, between consecutive standard releases not as much
             | changes; it's pretty clear that they're the same language
             | with some slight differences/new features. I think the
             | point is C++ has had so much change over the years it
             | almost seems unrecognizable compared to its earlier forms.
             | 
             | Almost makes me think of the ship of Theseus. How do we
             | define the point that it's so different it could be
             | considered a different language? Backwards compatibility
             | strikes me as a factor, but backwards compatibility is
             | violated by languages all the time and it's still
             | considered "the same language."
        
       | olliej wrote:
       | The bug report says that the lambda pointer is dangling and is
       | leaked. I'm not at my computer atm so i can't tell which this is
       | (by my definition dangling = security bug, leak = annoying, both
       | are bad the former is obviously much worse), my intuition is that
       | it's a dangling reference but not in a position to see codegen
       | (I'd guess something similar occurs in clang if it's spec
       | behaviour). Given that this is the obvious use case I feel that
       | this would be worth fixing in the spec before widespread
       | adoption.
       | 
       | That all said it demonstrates the issues with a lot of new c++
       | features, in that even today new features are added without real
       | thought to memory safety. There were a couple of proposals to at
       | least make it possible to specify lifetime constraints, even if
       | they'd only be warnings initially, but they died because memory
       | safety remains a lower priority than other sexier features.
       | 
       | Like I really do love c++, but memory safety has to become higher
       | priority than other features for a while.
        
         | j-krieger wrote:
         | > That all said it demonstrates the issues with a lot of new
         | c++ features, in that even today new features are added without
         | real thought to memory safety
         | 
         | I would go much further than that and claim that there are new
         | C++ features added without real thought to _other features_.
         | The C++ feature list is so incredibly vast that language
         | maintainers  / spec writers would need to know every little
         | intricacy of other features to assert that a combination would
         | still produce correct output.
        
           | asveikau wrote:
           | We're now 11 years from c++11, but I wanted to say lambdas
           | are generally well thought out with respect to how memory
           | management works in c++. The syntax for captures is weird at
           | first, but once you appreciate that what it's doing is
           | playing nice with copy constructors, it's good.
        
           | AlotOfReading wrote:
           | The problem is so much worse than that. Combining even the
           | most fundamental features of the language (like UB and
           | concurrency) leads to dark corners where even experts like
           | Boehm aren't sure. The recent TR about safety-critical C++ is
           | basically "don't use C++", which is correct, but not
           | particularly helpful.
           | 
           | The reality is that the standard simply isn't a good enough
           | reference for what the language does. If you care about that,
           | you need to treat programming in it as an experimental
           | endeavor where you validate that your particular combination
           | of code + toolchain + hardware does what you want. It's nice
           | if the standard goes along for the ride, but not something
           | you can rely on.
        
         | notacoward wrote:
         | This is what _always_ seems to happen when systems only grow
         | and never shrink. Later-added features don 't always play well
         | with each other, even when they're added sequentially and it
         | seems like they should. It's technical debt at the
         | specification level (as opposed to code) and I've seen it bite
         | more projects than I can count.
         | 
         | Sometimes you just have to start swinging the axe, or else stop
         | wasting effort and plan migration to an alternative. In this
         | case the alternative seems to be Rust, and no, I'm not a Rust
         | advocate. Far from it, in fact. Personally I find Zig and
         | several others more appealing. However, I also feel that the
         | state of the art will advance more quickly if the C++
         | programmers migrate to _any_ of those alternatives, and Rust
         | seems pretty far ahead as the direct successor.
        
         | masklinn wrote:
         | In fairness, features which break one another are not a new
         | thing in C++.
         | 
         | > they died because memory safety remains a lower priority than
         | other sexier features.
         | 
         | Is it a priority at all? Or is it on a list titled "!" under a
         | cabinet in the disused toilets of the third basement?
         | 
         | I don't know whether 20 did as well, but C++17 literally added
         | explicitely anti-memory-safety features (std::optional).
        
           | kllrnohj wrote:
           | > but C++17 literally added explicitely anti-memory-safety
           | features (std::optional)
           | 
           | How did you reach the very odd conclusion that std::optional
           | is "anti-memory-safe"?
        
             | masklinn wrote:
             | Because the committee took something which is normally a
             | way to lift nullability into the type system and make
             | pointers null-safe, and instead made it... a nullable
             | pointer. With all the absence of safety of a C++ pointer.
        
               | jcelerier wrote:
               | > Because the committee took something which is normally
               | a way to lift nullability into the type system and make
               | pointers null-safe, and instead made it... a nullable
               | pointer. With all the absence of safety of a C++ pointer.
               | 
               | anything that adds a branch to check dereference in
               | release builds is an instant no-go, what do you propose
               | to do instead?
        
               | pornel wrote:
               | That "instant no-go" is the problem. C++ is still
               | unwilling to budge even a tiniest bit for safety.
               | 
               | In most scenarios there has to be a check _somewhere_.
               | Where C++ got it wrong is allowing separation of the
               | check from the use of the now-known-to-be-set value, so
               | the necessity to have convenient zero-cost _unchecked_
               | use is a problem C++ has created for itself.
               | 
               | Safe languages solved this by carrying the checked state
               | over using the type system (e.g. pattern matching or flow
               | typing), so further the uses after the check are free AND
               | guaranteed safe.
               | 
               | There are some situations where the state of the optional
               | being set is known from the context, but in a convoluted
               | way too complex for the type system to follow. C++
               | focused on supporting this case -- unwilling to
               | compromise on either syntax or performance, and
               | sacrificed safety for it.
               | 
               | Other languages in such muddy scenario either take the
               | cost of a branch or have an unchecked-unsafe function for
               | optimization, but importantly -- that function doesn't
               | get a syntax sugar. It is meant to stand out as a rare
               | risky operation, and not be hidden behind super common
               | innocent-looking syntax.
        
               | CJefferson wrote:
               | Why is it a no-go? If you mark the check as "unlikely"
               | the cost is extremely small, and maybe we should just pay
               | the cost rather than have undefined behaviour.
        
               | jcelerier wrote:
               | > the cost is extremely small
               | 
               | until it isn't, i've seen branches eat 10-15% of hotspots
               | sometimes. but honestly, in practical terms, I shouldn't
               | complain if people want that: that's literally more
               | consulting money in performance consulting for me
               | afterwards :-)
               | 
               | let me repost one of my own past comments with a quick
               | and dirty benchmark:
               | https://news.ycombinator.com/item?id=30867368
               | 
               | I have been paid hard money for performance improvements
               | _much smaller_ than something like this in my life
        
               | kouteiheika wrote:
               | > anything that adds a branch to check dereference in
               | release builds is an instant no-go
               | 
               | ...which, as shown by Rust, is actually not true, and is
               | very much a go in the vast majority of cases.
               | 
               | > what do you propose to do instead?
               | 
               | It's easier and more natural to access the optional in an
               | unsafe way (through the -> operator) than access it in
               | the safe way (through `value()`); this is a wrong default
               | which should have been made the other way around.
               | 
               | Potentially unsafe behavior should be opt-in, instead of
               | opt-out. Yes, it's important that you have the option to
               | disable this check for performance-sensitive code. But
               | the majority of the code is _not_ performance-sensitive
               | to this degree that an extra branch is going to make any
               | difference whatsoever.
        
               | kllrnohj wrote:
               | > It's easier and more natural to access the optional in
               | an unsafe way (through the -> operator) than access it in
               | the safe way (through `value()`); this is a wrong default
               | which should have been made the other way around.
               | 
               | Then it's inconsistent with std::vector & similar.
               | Consistency across the standard library seems much more
               | worthwhile, especially here where it's pretty obvious
               | when you mess up using a std::optional (like just never
               | checking if it has a value, which jumps out in code
               | reviews quite clearly)
        
               | kllrnohj wrote:
               | std::optional is not limited to pointers, and it has the
               | safety if you want it - use value().
        
               | electroly wrote:
               | There are some platforms that provide std::optional but
               | not value()! macOS 10.13 is one of them. You're forced to
               | use the unsafe * operator on that platform. I cannot
               | imagine the rationale that went into shipping
               | std::optional support without value(), but they did it.
        
             | hvdijk wrote:
             | std::optional can be described as memory-unsafe because
             | indirection when an optional is empty has undefined
             | behaviour rather than deterministically throwing an
             | exception or aborting the program, and may misbehave in all
             | sorts of spectacular ways, including accessing random
             | memory, on common implementations. Thankfully,
             | implementations can and do provide ways to get it to behave
             | more predictably.
        
               | kllrnohj wrote:
               | But that's not actually true in general.
               | std::optional<int> has no such indirection issues, for
               | example.
               | 
               | If you're saying that blindly calling `operator->` on a
               | std::optional<int*> without ever checking has_value() or
               | similar can result in dereferencing garbage then yes,
               | sure? But calling that "explicitly memory-unsafe" seems
               | misleading at best, and just aggressively wrong at worst.
               | You can always use `value()` if you want an error-
               | throwing option, just like std::vector has at(). The
               | standard didn't just ignore that.
        
               | spoiler wrote:
               | I think the phrasing of "explicitly memory-unsafe" is
               | wrong[1] in letter, but true in spirit. At the end of the
               | day `std::optional<T>` is only _marginally_ better than
               | `T*`. And I 'm sometimes not even sure if it's better or
               | worse; the extra API surface you describe is nice, but in
               | practice it's just a mirage of safety, since its API
               | subset includes that of a common pointer. And I've seen
               | ample code use the unsafe API because
               | (convenience/performance/inexperience).
               | 
               | But at the end of the day, I guess my comment is also
               | irrelevant, because we as developers should strive for
               | correctness, not brevity, in code. If we can achieve
               | both, the better. But alas, brevity and correctness are
               | in an antagonistic tension in C++. So when we want
               | correctness in C++, we should also be prepared to swallow
               | a large portion of spaghetti Bolognese.
               | 
               | [1]: Or at least no more melodramatic than the phrase
               | "aggressively wrong" lol
        
               | kllrnohj wrote:
               | > At the end of the day `std::optional<T>` is only
               | marginally better than `T*`.
               | 
               | It's dramatically better than `T*` if your data isn't a
               | pointer in the first place.
        
               | hvdijk wrote:
               | Sure, std::optional<int> is unlikely to result in such
               | behaviour in practice, and std::optional<int*> is likely
               | to "only" result in such behaviour if the result of
               | operator*() is dereferenced again, despite both already
               | being UB. Think of non-POD types, such as
               | std::optional<std::string>, though: when you end up using
               | uninitialised std::string objects, things do break in
               | practice because of pointers used internally to implement
               | std::string, and badly so.
               | 
               | The fact that checked versions exist but are not used by
               | default, have to be explicitly opted into, is consistent
               | with C++'s designs and may be used to defend the current
               | design, but at the same time also means it describing
               | std::optional as memory-unsafe becomes a valid opinion
               | based on facts, I think.
        
               | kllrnohj wrote:
               | > but at the same time also means it describing
               | std::optional as memory-unsafe becomes a valid opinion
               | based on facts
               | 
               | But your "facts" are "if I use the API wrong, it behaves
               | wrong." But std::optional isn't easy to accidentally
               | misuse here, unlike string_view (an actually "unsafe"
               | addition). The argument that optional is broken if you
               | both don't use has_value _and_ don 't use any of the
               | other helpers (like value_or() or value() or transform or
               | etc...) then it has UB means that optional is "broken by
               | design" is not a very strong position to take.
               | 
               | It's hard to imagine this being a problem in practice.
               | It's pretty encoded in the code that it's optional, to
               | just completely ignore that and blindly access it anyway
               | seems pretty self-evident as a usage issue. Yes bugs
               | happen, but come on. This is not a particularly sharp
               | edge in C++'s toolbox here. It's a pretty
               | straightforward, intuitive type, doing pretty much
               | exactly what it says it does, exactly how you'd expect it
               | to do.
               | 
               | Should operator->() and value() be swapped? _maybe_ , but
               | then it'd be inconsistent with std::vector & other older
               | types. And that inconsistency is probably worse overall.
        
               | hvdijk wrote:
               | > But your "facts" are "if I use the API wrong, it
               | behaves wrong."
               | 
               | Kind of, yes. That is what memory safety is about, isn't
               | it? If I look for definitions, I find for instance
               | <https://hacks.mozilla.org/2019/01/fearless-security-
               | memory-s...>, explaining it as:
               | 
               | > When we talk about building secure applications, we
               | often focus on memory safety. Informally, this means that
               | in all possible executions of a program, there is no
               | access to invalid memory. Violations include:
               | 
               | > - use after free
               | 
               | > - null pointer dereference
               | 
               | > - using uninitialized memory
               | 
               | > - double free
               | 
               | > - buffer overflow
               | 
               | std::optional does not itself protect against using
               | uninitialised memory, it merely provides the tools by
               | which the programmer can prevent using uninitialised
               | memory. Isn't that exactly what memory safety is about,
               | about having std::optional somehow automatically ensure
               | that that doesn't happen? If that isn't what memory
               | safety is, what, in your opinion, does it mean instead?
               | 
               | Note that I have attempted to refrain from posting my
               | opinion on whether C++ made the right call or not. That
               | is a separate question from whether it qualifies as
               | memory-safe.
        
               | kllrnohj wrote:
               | I'm not arguing that c++ is memory safe, it isn't. But
               | the initial claim is that std::optional is "explicitely
               | anti-memory-safety". And _that_ seems like a very
               | unsupported claim. std::optional isn 't safer than the
               | rest of C++, but it's definitely not _less safe_ either.
        
               | hvdijk wrote:
               | Ah, thanks for the clarification, I think we've been
               | talking about two slightly different things, then. For
               | you, std::optional would have to make C++ more memory-
               | unsafe than it already is in order for "anti-memory-
               | safety" to be a fair characterisation. For me, that label
               | merely implies that memory-safer alternative designs of
               | std::optional were considered, and the current design was
               | picked despite its memory-unsafety being a known
               | potential issue. I think I would likely agree with you
               | that std::optional does not make C++ less memory-safe
               | than it already was before that got added.
        
       | jiripospisil wrote:
       | The discussion continued over at "std-proposals"
       | https://lists.isocpp.org/std-proposals/2020/05/index.php#msg...
        
       | Ygg2 wrote:
       | Needs 2020 tag.
        
       | varelse wrote:
        
       | j-krieger wrote:
       | Putting the discussion about C++ memory safety and concurrency
       | issues aside, I am pretty astonished that C++ continues to
       | include bugs where you have two actual _language features_ - not
       | library functions - which on their own work perfectly fine, but
       | combining the two makes the entire thing silently implode.
       | 
       | I am trying very hard to imagine any other higher level language
       | where two distinct language features, each used correctly in
       | their own way, can not be safely combined. The only thing that
       | comes to mind are python's default parameters and passing an
       | empty list as one.
       | 
       | C offers total freedom in exchange for providing ways to shooting
       | yourself in the foot. All of its "dangerous" features _can_ be
       | used correctly for some benefit. With C++ it feels like to me
       | like that benefit is often lost entirely, and whats left is just
       | incorrect code that for some reason passes by the compiler
       | without error.
        
         | eloff wrote:
         | I've always thought of C++ as the most complex programming
         | language I know. With each revision it becomes more complex. I
         | gave up and just moved on to Rust a year and a half ago. I have
         | no regrets.
         | 
         | C++ has not quite joined Perl, PHP, and Java as languages I
         | will not work with anymore, but it's the next logical
         | candidate.
        
           | tasubotadas wrote:
           | No idea why you decided to lump Java together with these
           | abonimations.
           | 
           | Java by itself is an extremely simple language.
        
             | eloff wrote:
             | In theory Java is not so bad. I just have never enjoyed
             | working with it or with the code Java developers end up
             | creating. Kotlin is reasonably pleasant. I've sometimes
             | used it when the JVM was a hard requirement.
        
             | marginalia_nu wrote:
             | Java is like one of those ice berg memes with a lot of
             | byzantine JVM shit lurking at the depths.
        
           | bugfix-66 wrote:
           | I used C++ full-time for more than a decade before finally
           | abandoning it in disgust.
           | 
           | Now I use Go for most purposes, and C or CUDA when
           | appropriate.
           | 
           | Good riddance.
        
           | spoiler wrote:
           | I've not worked with PHP for over 8 years now, but I hear
           | it's gotten much better recently.
           | 
           | It still has issues that are commonly associated with hosting
           | provider configuration/control over the runtime, apparently.
           | 
           | (sources are anecdotal; two friends who've had the mental
           | fortitude to stick with the language for so long)
        
             | jmt_ wrote:
             | PHP 7 & 8 introduce lots of improvements. I used PHP 5 when
             | I got into web dev and remember moving to Python as soon as
             | I could. At work I've had to use PHP 7 and have been very
             | pleasantly surprised at how solid it is. Now that I have
             | more experience than my PHP 5 days, it's become apparent
             | that PHP is very clearly suited for web work and the built-
             | in functions offer many conveniences for such work that
             | simply aren't available in other languages (granted other
             | languages weren't built for web like PHP was). I've been
             | surprised by my speed in PHP and I chalk most of that up to
             | many helpful standard library functions. Even though PHP
             | has a lot of old/compat functions still present I'm always
             | surprised by how little that actually ends up effecting my
             | productivity. So it's not my choice for greenfield projects
             | but I'm not nearly as adverse to it now after working with
             | modern day PHP for a bit.
        
         | 0xbadcafebee wrote:
         | I find it unreasonable that every language would have all of
         | its features always compatible. Why can't we just say "don't
         | use X and Y together" ? It might solve a ton of problems. All
         | you have to do is have a big red warning in the manual that
         | says _DON 'T COMBINE X AND Y_, and a language feature that lets
         | you turn on X and turn off Y.
        
           | CJefferson wrote:
           | Who reads the "manual of C++" -- what even is that, the
           | standard document (certainly no-one should read that for
           | learning).
           | 
           | It would be just about OK for the compiler to refuse to
           | compile X and Y together.
           | 
           | If you "switched off" X, then in C++ (where code is in
           | headers which are just concatenated with your code), this
           | would effectively split the language, as you also couldn't
           | use libraries which use X in their headers.
        
           | jejones3141 wrote:
           | Orthogonality has been recognized as desirable at least since
           | the days of Algol 68. Once you couldn't pass a struct as a
           | parameter in C. Now you can.
        
           | [deleted]
        
           | j-krieger wrote:
           | > Why can't we just say "don't use X and Y together"?
           | 
           | Because that goes against the most fundamental idea of
           | programming languages that you can build larger abstractions
           | by combining basic building blocks.
        
             | travisgriggs wrote:
             | Abstractly speaking, what if we consider a "big ball of
             | spaghetti" and "working program" to both be abstractions of
             | just "a program". Now it fits under the larger abstraction
             | umbrella still. :D
             | 
             | All other things aside, C++ seems to be the language "to
             | big to fail" and so it just keeps getting more and more
             | features added to keep it competitive.
        
             | [deleted]
        
             | 0xbadcafebee wrote:
             | A half dozen languages already do this and abstractions
             | still work
        
           | extropy wrote:
           | Sure, here is your Lego set. But do not put while bricks next
           | to red ones or it will explode!
        
         | selimnairb wrote:
         | I have returned to using C++ over the last six-months after not
         | using it really since university 20+ years ago. I mostly write
         | Python these days, Java in the past, but have also recently
         | written some moderately complex and unsafe C (e.g., making a
         | parser using flex and bison; doing lots of void* pointer
         | arithmetic to get around not having runtime reflection). I am
         | astonished at the complexity of modern C++. I've studied Rust
         | and used some Swift (on an iOS app for a client a couple of
         | years back), and I struggle to "correctly" write code in C++. I
         | feel as if C++ is collapsing under its own weight.
        
           | TremendousJudge wrote:
           | Similar story here. I'm constantly wrestling with the tool
           | more than the actual problem I should be solving
        
           | curtis3389 wrote:
           | I programmed in C++ all through college, and I get the same
           | feeling watching its development.
           | 
           | TR1 brought the language to a pretty good place with smart
           | pointers, and at first C++11 looked awesome with its type
           | inference features and range-based for loops.
           | 
           | But, also in C++11 were tons of weird gotchas with new and
           | old features. The one that comes to mind is the uniform
           | initialization. It was supposed to fix the issues with
           | calling regular constructors, so you could just use the new
           | syntax and not worry.
           | 
           | But, they also added initializer lists, and those have issues
           | with uniform initialization, so now you not only need to know
           | all the pre-existing issues with the old syntax, you need to
           | know the new syntax and its issues.
           | 
           | This all comes back to C++ refusing to break backwards
           | compatibility, which is great and all, but at this point
           | they've made a language that is only good for job security.
        
           | synergy20 wrote:
           | what exactly are them? I'm also back to modern c++ but I plan
           | to only use a subset of the super set to make life easier.
           | for example I don't need write a c++ library so many of the
           | new (meta-template-programming) feature I don't need to pay
           | attention to at least for now.
           | 
           | what I really need are RAII, smart pointer, the STL library
           | and algorithms basically, plus simple OOP use cases, those
           | combined are not very complicated to me.
        
         | masklinn wrote:
         | > I am trying very hard to imagine any other higher level
         | language where two distinct features, each used correctly in
         | their own way, can not be safely combined. The only thing that
         | comes to mind are python's default parameters and passing an
         | empty list as one.
         | 
         | And even then it's not a bug per-se, at best a misfeature (it
         | can be useful as a performance hack although the performance
         | improvements of global and builtins lookups of 3.11 might
         | finally put that to rest).
        
         | hellcow wrote:
         | > I am trying very hard to imagine any other higher level
         | language where two distinct language features, each used
         | correctly in their own way, can not be safely combined.
         | 
         | Handling JavaScript exceptions as opposed to promise rejections
         | in async code is a continual source of pain. They don't work
         | together. If you do try/catch on async code but forget to call
         | await, catch will never be hit and your program might crash.
         | There appears to be no linter available to detect this. Unless
         | I've completely missed something, the interaction between these
         | two features is a terrible design.
        
         | avgcorrection wrote:
         | There are two sorts of languages: languages with a coherent
         | feature set and those that people actually use. Wait hold on,
         | that doesn't apply here...
        
         | kllrnohj wrote:
         | > C offers total freedom in exchange for providing ways to
         | shooting yourself in the foot. All of its "dangerous" features
         | can be used correctly for some benefit.
         | 
         | C is pretty archaic in its feature set, so it's not surprising
         | it doesn't have many language features that don't work well
         | together since it doesn't really have any language features in
         | the first place. That's not necessarily a _good_ thing, either,
         | but that 's a different discussion.
         | 
         | > With C++ it feels like to me like that benefit is often lost
         | entirely, and whats left is just incorrect code that for some
         | reason passes by the compiler without error.
         | 
         | That's an odd statement to make here. Yes this is an
         | unfortunate combination that results in memory leaks, but how
         | is C's "everything is a memory leak" any better? 100% broken is
         | better than 10% broken?
         | 
         | That said, I do wish C++ hadn't added coroutines in the first
         | place. It feels like a weird addition to the language. Then
         | again, I also wish Rust hadn't added them, either. They are
         | nightmarishly complex in a non-GC'd language, and the benefits
         | are far from clear. The "colored function" problem remains a
         | hotly debated topic, and low-level, performance-focused
         | languages (like C++ & Rust) feel like the very wrong place to
         | hammer on those topics.
        
           | j-krieger wrote:
           | > That's an odd statement to make here. Yes this is an
           | unfortunate combination that results in memory leaks, but how
           | is C's "everything is a memory leak" any better? 100% broken
           | is better than 10% broken?
           | 
           | Because if you use features that may leak memory, you can
           | still trust yourself as a programmer. If you cant even trust
           | the language / compiler, I would consider that worse.
           | 
           | > Then again, I also wish Rust hadn't added them, either
           | 
           | I agree.
        
           | dtgriscom wrote:
           | > Yes this is an unfortunate combination that results in
           | memory leaks, but how is C's "everything is a memory leak"
           | any better? 100% broken is better than 10% broken?
           | 
           | I'd rephrase "100% broken" as "always does what it says it
           | will", and "10% broken" as " _almost_ always does what it
           | says it will. " I'd prefer the former 99% of the time.
        
           | notacoward wrote:
           | > C's "everything is a memory leak" any better?
           | 
           | That's a bit hyperbolic, unless you apply the same phrase to
           | any language (including C++) without a full tracing garbage
           | collector or equivalent. X leaking a resource is not the same
           | as X returning a resource that the caller is explicitly
           | responsible for freeing. Further, C _in practice_ is not as
           | bad as you portray. Maintainers of large open-source
           | projects, of which I used to be one, often define their own
           | memory-management facilities and rules which are just as good
           | as C++ 's in preventing leaks for most code. I think they
           | shouldn't need to nowadays, and that C would be a poor choice
           | for a new project at any level, but that's easily shown
           | without resorting to hyperbole.
        
         | dkackman11 wrote:
         | Agree. Modern C++, and discussions around it, become more
         | esoteric with every revision. As software engineers we should
         | spend our time understanding the esoterica of the problem
         | domain, not the toolset.
        
           | hdjjhhvvhga wrote:
           | I'm of the same opinion. Frankly, when Go first appeared, I
           | felt we would finally get something almost as simple as
           | Python and almost as fast as C. Unfortunately not everything
           | was as nice as I had expected. Still, in that respect it's
           | better than Rust as it makes it easier to focus on the
           | problem rather than the language.
        
             | xyzzy4747 wrote:
             | I personally still don't understand the benefit of Go vs
             | Java? They seem to accomplish similar things with similar
             | amounts of boilerplate.
        
               | tomohawk wrote:
               | Having used both professionally (several years each), Go
               | is massively simpler than Java, at least for the problems
               | we tackle. We sometimes will get a new dev on the team
               | from Javaland, and the biggest thing for them is
               | unlearning all of unnecessary complexity. YMMV.
        
             | _wldu wrote:
             | The complexity of C++0x is one reason Go was created.
             | 
             |  _" For me, the reason I was enthusiastic about Go was just
             | about the same time we were starting on Go, I read (or
             | tried to read) the C++0x proposed standard. And that was
             | the convincer for me."_ - Ken Thompson
             | 
             | 17:45 mark here: https://www.youtube.com/watch?v=sln-
             | gJaURzk
        
       | [deleted]
        
       ___________________________________________________________________
       (page generated 2022-10-04 23:01 UTC)