11 ms·
To summarize: 1) Rust's standard idioms (in this case, Results and Iterators) encourage less bug-prone or ambiguous APIs (standard and otherwise) 2) Rust's ec
by brundolf 6y ago
To summarize:
1) Rust's standard idioms (in this case, Results and Iterators) encourage less bug-prone or ambiguous APIs (standard and otherwise)
2) Rust's ecosystem makes it easy to find and integrate solutions not offered by the standard API
3) And then finally, Rust's borrow checker prevented a threading issue
Others are rightly pointing out that only #3 is fundamentally unique to Rust. All of these other things could be done for C++. But, importantly, they haven't.
This raises an interesting dimension to the comparison which is that many of Rust's advantages don't really come down to its unique traits (heh) but to the simple fact that it's "C++ without baggage". It had a fresh start when it came to establishing standard idioms for everyone to use, providing cross-platform tooling for everyone to use, providing centralized package management for everyone to use, etc. If you introduced to C++ a Result type, or a package manager (I assume people have done this already), most C++ developers wouldn't end up using them. Most libraries wouldn't be using the same vocabulary. It would be arduous to even move the standard library over, because it would be a breaking change. Much of the tooling out there would probably never get specialized support.
I don't think these network effects and cultural forces get talked about enough. Sure, this stuff is "just a library", and C++ has libraries. But the culture and the baggage and the stakeholders around a language have a huge impact on what ends up being practical to do with it, independent from what's technically possible.
- zabzonk 6y ago> If you introduced to C++ a Result type I don't know too much about the details of rust, but: std::optional? Whether people will use it is of course up to them, but my feeling is that they will.
- steveklabnik 6y agoNot the same, Optional is like Option in Rust, it’s about existence, not success or failure. I believe std::expected is the correct answer but it’s unclear to me if it actually made it into the standard yet or not. I thought it had but can only find proposals...
- zabzonk 6y agoAFAIK its not yet into any standards, possibly because the semantics are really complex (don't know how rust specifies them) - useful discussion here: https://www.reddit.com/r/cpp/comments/c75ipk/why_stdexpected_is_not_in_the_standard_yet_is_it/ https://www.reddit.com/r/cpp/comments/c75ipk/why_stdexpected...
- shaklee3 6y agoIsn't Optional used in a lot of cases where empty means failure?
- marcosdumay 6y agoThat's not enough. Hacking failure reporting into an existence API will make your code confusing, and will leave you no way to report multiple types of errors.
- steveklabnik 6y agoIt might be, but that doesn’t make it semantically the correct thing. As always, it depends. But traditionally, most languages that use this strategy have both, and they aren’t interchangeable. I can see this happening more when you only have optional, though.
- secondcoming 6y agoThere are proposals for std::outcome and std::expected. I think the internal workings for one of them have also been passed to the C committee for standardisation.
- leetcrew 6y agofrom a safety perspective, std::optional is not much different than std::unique_ptr. both will happily allow you to invoke UB if you don't explicitly check for validity.
- yakubin 6y agostd::optional is like Rust's Option. But even then, without compile-time pattern-matching you leave the error to be checked at runtime, which defeats the purpose of this type. On top of that, it wouldn't be C++ if there wasn't some UB involved.
- pornel 6y agooperator*() and operator->() on an empty std::optional is Undefined Behavior. This is mind-boggling. It defeats the whole purpose of using a wrapper type to enforce bulletproof error checking. It's the worst of both worlds: you have to use a cumbersome type, and it still fails like a nullable pointer.
- leetcrew 6y agoyes, it is a somewhat baffling feature. the only practical use I can imagine for it is to avoid calling the copy constructor with an invalid instance of the type and/or to avoid a heap allocation. otherwise, it would be much more natural (and no less safe) for a c++ programmer to just use some flavor of pointer. in the case of pair<bool,T>, one would expect an optimizing compiler to skip the constructor call for an invalid instance anyway if the object was only accessed after checking the bool (unless the constructor has side-effects, yikes!).
- saagarjha 6y agoI think most of this is just because C++ doesn't have very good pattern matching and didn't want to introduce new operators. (FWIW, using operator*() and operator->() feel very natural, although they are unsafe without using operator bool() as you have mentioned.)
- skohan 6y ago> 2) Rust's ecosystem makes it easy to find and integrate solutions not offered by the standard API This is a double-edged sword. I'm a huge fan of Rust's tooling, but when it's so easy to add dependencies, this inevitably leads to deep dependency trees, slower compile times, and less knowledge about what's actually happening inside most rust code bases. Often times when asking about how to solve a problem in Rust, the answer comes in the form of "use crate X" rather than an explanation of how to solve the problem using the language itself.
- serial_dev 6y agoI think it's important to say the silent part out loud: "just use crate x and you can look up how the crate works behind the scenes if you are curious".
- hannofcart 6y agoThis statement is a bit confusing: are you saying that there is such a thing as too much code reuse? That it should be necessarily a bit difficult to integrate a third party library in your codebase?
- skohan 6y agoThere's always a balance point. For something like JSON parsing, or an HTTP client, for sure I want to use a library. But when code reuse means pulling in a giant library to do one specific thing, or else introducing a runtime like tokio where it otherwise might not be needed, I would probably rather implement a small tailored solution specifically for my use-case.
- Measter 6y agoIn one sense, the way that larger crates in Rust are fragmented does address some of that. This does result in large dependency trees, but it does also mean that if you need that one specific functionality, you may not need to pull in the full library, but only that smaller section.
- 6y ago
- shmerl 6y ago> but to the simple fact that it's "C++ without baggage". That's how I've always viewed it. Or rather a better replacement for C++.
- pjmlp 6y ago> Others are rightly pointing out that only #3 is fundamentally unique to Rust. All of these other things could be done for C++. But, importantly, they haven't. Except they have, but some people aren't keeping up with C++ news, only bashing it. 1) can be easily done with bounds checked enabled STL, like modern C++ compilers do in debug builds, or force enable them in release builds. 2) Conan, vcpkg, and better than cargo, because they support binary dependencies.
- RazrFalcon 6y ago>because they support binary dependencies Without an ability to tweak build flags. Which makes them useless. And since they are not really crossplatform either, you better stick with portage, which is still far behind cargo.
- pjmlp 6y agoSo useless, that they get used daily by millions of C++ developers, and was one of the top requested features for vcpkg. Sword fighting gets tiresome after a while, and not all businesses enjoy shipping source code anyway.
- Siira 6y agoI tested most cpp pkg managers (including vcpkg and conan); They suck. They suck so much that I reached the conclusion that using git submodules was the way to go, and saw “just copy the header file” in readmes of modern projects. The pkg managers are hard to install and configure, don’t integrate well with the tooling, don’t support most stuff, have out-of-date documentation, and are just buggy. Cpp API design also seems to suck. Doing a simple curl request is bloody complicated.
- pjmlp 6y agoYet millions of devs are adopting them every day, they might be really masochistics, like myself every time I rebuild from scratch my Rust compile time check, that with compiling everything from scratch takes 18 minutes on average laptop, versus 5 minutes in C++ (thanks binary libs). Cargo keeps failing my litmus test for usability of compiled languages. I just look forward that something like Cranelift will fix it.
- aeturnum 6y ago> All of these other things could be done for C++. But, importantly, they haven't. I think programmers often under-emphasize the importance of culture, so I want to boost this line. Lots of "debates" around programming languages are, I think, better understood as differences in beliefs about what a language should prioritize. C++ could add an allocation checker that provides stronger memory guarantees by outlawing certain operations (or requiring they be marked a'la `unsafe`). They don't add it because, I think, they view other additions to the language as having a higher "return" on allowing people to create high quality programs. It seems to me that a lot of this comes back to first-principles about what makes a good programming language. These ideas are, to some degree, set before a line of code is written. The rust folks thought memory and concurrency safety were very important when they were designing rust - even though they couldn't have formed those opinions by using the kind of language they were making (because nothing quite like it existed yet). I also think about "infamous" qualities of languages (generics in go, the GIL in python). These ideas exist within wider cultural beliefs about what makes a good programming language. In a sense, it's inevitable that most of the people working on cpython aren't too concerned about the GIL, because they chose to work on a project that has developed around the GIL and believe its limitations are worth the gains from being able to rely on its coordinating function. The implications of this are, to me, that when advocate for languages to adopt features we'd like to see we should remember the wider cultural context. It seems silly to expect the current golang team to implement generics "the way the community wants" because they've spent years building a fully featured language that functions without generics. Culture runs deep and it's not an intellectual or professional flaw to value improvements differently than our peers.
- sk2020 6y ago>nothing quite like it existed yet. Cyclone has been around some 2002 according to Wikipedia. I don’t think a similar language (RAII + annotations + a mostly-mandatory validation step in the compiler) has had a well funded and sustained marketing campaign until rust, though. RAII also predates Rust by a couple decades. Rust is also not very similar to itself from its early days.
- aeturnum 6y ago
- pierrebai 6y agoC++ multi-threading is easy by not sharing data. Just have each thread produce a result and have a thread that accumulates the results via std::future. I've converted many mono-thread C++ algorithm this way.
- ledgerdev 6y ago> 2) Rust's ecosystem makes it easy to find and integrate solutions not offered by the standard API This made me think back to something Rich Hickey said in his "Are we there yet?" talk. In short rust has memory management, and so can better function as a library language, similar to how Java did back in the 90's. Rich's quote below. >> And it is a big problem. I think the lack of garbage collection really impeded C++ in one of its design objectives, which is: it was supposed to be a library language. All the original design stuff and any time you heard Stroustrup talk about it, it is like, "C++ is going to be a library language". But it only ever ended up being a parochial library language. Every shop had a library, but there were not a library, and still are not a lot of libraries, that go between places, because of this problem. https://github.com/matthiasn/talk-transcripts/blob/ccc4a017294f6b6abdf62f47aa41298f93250af6/Hickey_Rich/AreWeThereYet-mostly-text.md https://github.com/matthiasn/talk-transcripts/blob/ccc4a0172...
- overgard 6y ago> If you introduced to C++ a Result type, or a package manager (I assume people have done this already), most C++ developers wouldn't end up using them. Most libraries wouldn't be using the same vocabulary. It would be arduous to even move the standard library over, because it would be a breaking change. Much of the tooling out there would probably never get specialized support. CMake kinda makes me think there's definite interest in this kind of thing in the C++ community. It's janky and horrible, but it has tackled the module/package/library issue a little bit (not in an elegant sense but its a little more standardized)
- kenniskrag 6y ago> or a package manager (I assume people have done this already), Conan, the C/C++ Package Manager [1] [1] https://conan.io/ https://conan.io/
- ashtonkem 6y agoThere’s no real thing preventing #1 from being done in C++, but it is incredibly hard to remove bad patterns from a language that allows them. This is both problematic because these languages don’t provide first class support to remove unwanted features, and because huge amounts of existing code will use patterns you’re hoping to excise. In order to successfully do this you have to do a huge amount of both linting and dependency checking, and the resulting requirement that you not use any existing libraries makes using Result in C++ about as hard as doing a progressive rewrite into Rust.