7 ms·
For a really unpopular opinion: I prefer modern C++20/23 to Rust. For 98% of tasks Rust is incredible. But modeling those 2% of problems that don't fit neatly
by gavinray 4y ago
For a really unpopular opinion:
I prefer modern C++20/23 to Rust.
For 98% of tasks Rust is incredible. But modeling those 2% of problems that don't fit neatly into Rusts domain, the level of "unsafe", "PhantomData", and advanced type-system hacks you need feels obscene when I can use some pointers in C++.
Rust also does not have a compelling platform/story baked into the std for low-level asynchronous programming.
High level Mutexes and locks are there, but you're in for a world of hurt if you want to do something like sharded/striped locking, where the actual data being protected isn't directly owned by the lock (see Tokio's "OwnedMutexGuard" for this, thanks to Alex Chi and Victor Yang for telling me about this)
- worik 4y agoYes. Any system like Rust will have corner cases where it is awful. The simplest example is doubly linked lists, specifically, and any circular data structure in general. They are hard in any language to get right, but for all its sweat and pain Rust is no help here. C++ is a better choice.
- gavinray 4y agoI will openly say I think Rust is an all-around better language. If you are building general-purpose systems software, or just want to write fast software, use Rust. If you are fiddling with bits, doing low-level concurrency, writing a GC/Memory Manager etc, or have self-referential datastructures like graphs or trees, you're going to have an order of magnitude easier time writing it in C++. (Rust-experts excepted) Also, the developer experience writing C++ is worse than Rust by miles. Though the tooling (fuzzing, LSP, debugging, sanitizers, etc) is stellar, likewise with Rust.
- rich_sasha 4y agoI agree with this, but also sadly note structures like trees are sadly quite common, in the type of code I write anyway. It is a bit of a niggle I have with Rust.
- worik 4y ago> sadly note structures like trees are sadly quite common, in the type of code I write anyway. It is a bit of a niggle I have with Rust. Trees are no problem with Rust It is circular, rather than recursive, data structures that are troublesome
- rich_sasha 4y agoI had to use recursion to build a tree in AoC '22 day 7. I needed to have both a mutable stack of current tree nodes (`cwd` if you like) and the tree structure. Or equivalently a doubly-linked tree, where nodes point at their parent. It was a bit ugly. In C++ you just write it. I get why it's hard in Rust, just saying, it really does crop up.
- worik 4y agoYes. It is hard on garbage collection too, circular structures.
- pjmlp 4y agoTry the Rust development experience in Visual Studio or Clion versus C++, specially for stuff like GUI, DirectX or parallel debugging.
- gavinray 4y agoCLion is quite good you're right. I think it's the best of any Jetbrains IDE Visual Studio is also impressive, though I have a bit of bias against it from when it was so slow. (I know it's not the case now. It has a great debugging experience, that I don't think can be rivalled anywhere else.)
- pjmlp 4y agoExcept there is one thing C++ might never get, security culture. It is already better than C, as WG21 at least acknowledges there are some security issues and has taken multiple approaches to try to fix some of the underlying issues. However the way defaults are managed, versus the compiler provided frameworks from pre-C++98, are completely the opposite that security minded developers would wish for. The NSA cybersecurity bill seems to finally have hit home that this needs to change, however it remains to be seen if those at ISO that care about it will be able ot steer the ship around with their paper proposals like P2657R1, P2723R0,P2687R0. Bjarne keeps adocating the adoption of Core Guidelines and static analyzers improvements, which in a world where clang struggles to catch up, seems to have quite low priority in tooling improvements. In a way I guess it depends how relevant many key C++ frameworks and workloads (HPC/HFT/games/LLVM/GCC/FPGA/GUI) will evolve and what Rust can manage to take over.
- singularity2001 4y agoFor an even more unpopular opinion: I find the syntactic verbosity of Rust absolutely appalling: fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {} Surely this monstrous code has advantages over C(++) but in no world would I voluntarily write code in this language if other options were viable. I don't get how people prefer this language outside of a very narrow application context where the lasts millisecond of optimization matters.
- thecleaner 4y agoIt's easier to read if you split it into tokens and qualifiers. The & is a reference. The '_ is a lifetime parameter. The things in the <>are types. So this is a function which doesn't mutate self and takes a mutable reference to a formatter with a sensible lifetime and returns a result which will contain either nothing (or a unit) or an error if things fail. Thank you for posting this. I had to google and read up some things.
- nextaccountic 4y agoI think most of the gratuitous verbosity comes from qualifying smt::fmt::Error. If you import it, it becomes fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), FmtError> {} But the common practice is to have an alias Result<T> to mean Result<T, whateverErrorWeAreDealingWith>. This doesn't really maps well to doing impls in the Debug trait, since this trait uses an error that is generally different from the error defined by your own application, but with some care, it can be used. Then it becomes: fn fmt(&self, _: &mut Formatter<'_>) -> Result<()> {} Okay, but what about the whole rest? it's syntactically heavy, but each part of it is very significant. Take the <'_>. It means that the Formatter struct receives a lifetime parameter but you opted to explictly omit it. In previous Rust editions, you would keep it implicit fn fmt(&self, _: &mut Formatter) -> Result<()> {} But this was confusing and ambiguous! People looked at it and sometimes didn't know there is a lifetime involved - until it showed up in compiler error messages! Now, there's two elided lifetimes in this snippet: one in the &self and one in the &mut. Rust has clear rules for this case: your snippet means fn fmt<'a, b>(&'a self, _: &'b mut Formatter<'_>) -> ... Once you learn the rules (and here are the rules https://doc.rust-lang.org/nomicon/lifetime-elision.html https://doc.rust-lang.org/nomicon/lifetime-elision.html), this makes the syntax slightly lighter. It's not an issue like the other case because if you know the rule, it's not ambiguous. The _ in place of the variable name is there just to not give a name to the formatter. It's actually a catch-all pattern (like one in the end of a match). If you wanted to give a name but disable the unused lint, you would write _formatter instead. The rest, I can't really remove much sacrificing the semantics. The only superfluous thing I love is the ->, which is much better than the C convention of putting the return type before the function name (IMO). The <> syntax itself for generic parameters sucks, and it's about the worst thing that Rust inherited from the C++ syntax. The :: also sucks, and it's also from C++ (the turbofish ::<> combines both, and it was Rust's brainchild. https://turbo.fish/ https://turbo.fish/ [0]) Actually most C++ influences on the Rust syntax is a disaster. I would much prefer to have a Haskell-inspired syntax for types, so that the type Result<A, Box<C>> would be written Result A (Box C) [0] there were multiple attempts to remove the turbofish from the syntax. this thread has a discussion of it https://news.ycombinator.com/item?id=26019053 https://news.ycombinator.com/item?id=26019053 - also see https://www.reddit.com/r/ProgrammingLanguages/comments/fe3yg9/solutions_to_the_turbofish_problem/ https://www.reddit.com/r/ProgrammingLanguages/comments/fe3yg...