5 ms·
Fortunately, those can almost all be ignored almost all the time. Rust will seem fine until you are writing a library and find no way to express what would mak
by ncmncm 4y ago
Fortunately, those can almost all be ignored almost all the time.
Rust will seem fine until you are writing a library and find no way to express what would make the library nicer to use; or you find using some library awkward and error-prone. Almost every C++ feature is designed to enable delivering more powerful libraries, and they compound.
So, in C++ you as library writer are empowered to make the use of your library correct by construction: what compiles is safe and correct. Rust makes the compiler responsible for memory safety, but offers much less to make using your library pleasant and foolproof.
- volsa_ 4y ago> but offers much less to make using your library pleasant and foolproof Not my experience so far, I might go as far and say it makes it more foolproof because when writing your library you have the option to return an `Option` or `Result` enum.
- ncmncm 4y agoOption and Result types are as easily coded in C++. The former is in the Standard C++ library. The latter will be in the next, but anyway the one in Boost has worked fine forever. Throwing, instead, is a choice unavailable to Rust coders, so you often have no alternative but to return these more complicated things that users are then obliged to unpack. A standard macro makes that easier, and is semantically equivalent to throwing, but imposes substantial overhead on successful calls.
- Rusky 4y agoC++'s option and result types are much larger, uglier, and harder to use correctly than Rust's. The shift from throwing to returning a Result is not really an increase in complexity- closer to a reshuffling of syntax. But that's not really all that relevant either, because comparing languages at this level of detail misses the forest for the trees. An interesting comparison takes a step back and compares which problems the languages (try to) solve. Often something that appears to be a clear win for one or the other turns out to be a non-issue.
- ncmncm 4y agoThe substantial performance overhead, in Rust, of code to handle those types is unavoidable, even where source-level inconvenience has been minimized. Overhead is imposed all up and down the call chain, every time through. Seems pretty relevant to me.
- arinlen 4y ago> C++'s option and result types are much larger, uglier, and harder to use correctly than Rust's. What's your rationale for claiming in a swiping generalization that implementing a data type, regardless of all options or approaches and design, has no other option than doing everything wrong?
- Rusky 4y agoI mean, have you looked at them? C++'s standard library optional type is a tagged union implemented from scratch, with a dizzying array of template metaprogramming to meet the standard's requirements- see e.g. Microsoft's here: https://github.com/microsoft/STL/blob/main/stl/inc/optional#L214 https://github.com/microsoft/STL/blob/main/stl/inc/optional#.... This isn't a criticism of the team behind this code, it's just what it takes to do this in C++. Rust gets most of that functionality from the language instead, in a much cleaner way. Sum types are built in, value categories and move semantics are handled automatically, there is little-to-no metaprogramming, and most of the API is just simple convenience combinators with obvious implementations: https://github.com/rust-lang/rust/blob/master/library/core/src/option.rs#L518 https://github.com/rust-lang/rust/blob/master/library/core/s... If nothing else, this is a clear counterexample to the claim that "Option and Result types are as easily coded in C++."
- ncmncm 4y ago> it's just what it takes to do this in C++ False.
- LegionMammal978 4y agoDo you have any examples of how std::optional could be implemented more simply?
- mathstuf 4y agoThe fact that `std::optional<T&>` is verbotten makes them quite a bit more useless. The Boost one is better because it doesn't have this misguided limitation. It's really quite a sad story and a loss to all of C++ that it is this way (and not for lack of trying on ThePhD's part). > no alternative but to return these more complicated things that users are then obliged to unpack Yes, thank you. It is much better this way. I think "substantial overhead" needs to be backed up with some numbers here because setting up exception landing pads is certainly not free.
- chlorion 4y agoAccording to this link (posted below and includes benchmark results and a benchmark you can run), they compared result style error handling with conventional exceptions in C++, and the result style error handling (using an impl of std::expected) was "more than four times slower". According to the link and my understanding, exceptions are essentially "free" at runtime in the non-exceptional case on certain platforms such as Linux, but slower than result style error handling in the exceptional case. I prefer result style error handling personally and I am not suggesting that it's worse or shouldn't be used, just thought the findings were interesting and worth considering. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2544r0.html https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p25...
- mathstuf 4y agoSo I did some testing with Rust and I don't think that the C++ "four times slower" applies to it at first glance. Maybe Rust can just do better optimizations or something because Rust knows that it is a discriminated union, but these kinds of conclusions can't just be ported across languages blindly. Of course, porting the benchmark for `sqrt` wasn't trivial because (of course) C++ just modifies the span passed in making it easy to abstract out the allocations whereas Rust says "you cannot pass a mutable slice across a `catch_unwind` barrier", so all of my tests end up returning a new `Vec` inside the benchmarked function. I also wonder how much using an inner function for `fib` would allow some TCO to kick in and change results again. In any case, I don't think that C++'s has anything that satisfies the use cases that Rust's `Option` or `Result` cover in its standard library, so even if `std::optional` and `std::expected` were magically faster, the fact that `std::optional<inner_field_type const&>` is not supported means I can't use it for what I want anyways and I'm back to Boost or hand-coding classes and dealing with corner cases myself. Which is, unfortunately, a C++-shaped problem that has existed for a long time anyways, so…nothing new.
- oconnor663 4y agoI think Rust's combination of data-bearing enums and destructive move semantics goes a really long way towards letting library authors express their invariants through the type system. And that's in addition to the borrow checker and mutable aliasing rules. The mutable aliasing rules in particular are often kind of annoying for callers, but they're a godsend for API authors, because they allow for methods like Mutex::get_mut that don't even need to lock the Mutex, in safe code!
- mathstuf 4y ago> So, in C++ you as library writer are empowered to make the use of your library correct by construction: what compiles is safe and correct Empowered? Sure. But it seems no one likes using that power for long stretches of time. Rust gives the same power and it gets used far more usefully IME. > Almost every C++ feature is designed to enable delivering more powerful libraries, and they compound. Well, we can take `std::variant`, `std::optional`, and `std::expected` out of that pool because the committee hamstrung them from their better alternatives that already existed in Boost for silly, misguided reasons. > Rust makes the compiler responsible for memory safety, but offers much less to make using your library pleasant and foolproof. C++ libraries have, historically IME, been far more likely to ask you to juggle live grenades while dancing in a minefield than Rust libraries and APIs have.