5 ms·
I’m a pretty good C++ developer and have been trying to use Rust for a new project. The good: * Cargo! It’s amazing, thank you. * Portability. The build mode
by jonstewart 4y ago
I’m a pretty good C++ developer and have been trying to use Rust for a new project.
The good:
* Cargo! It’s amazing, thank you.
* Portability. The build model is the same between different platforms; all the time I waste managing multiplatform builds with C++ instead goes to coding.
* Libraries. C++’s stdlib has gotten a lot better, but it still can’t parse json or make web requests or create zip files.
* Community. The vibe from docs and blogs and videos is good, cheerful and optimistic.
The bad:
* The borrow checker. Memory safety is great but there are plenty of memory-safe designs that the borrow checker complains about. With modern C++ and sound design techniques, memory safety is not something I worry about much in my C++ projects, and the static analyzer proves me out on that. In particular, a typical application design involves some variation of the Observer pattern (implementations can vary wildly), where views read/“observe” models owned by controllers. Why should I beat my head against the wall with a systems language? There should be an escape valve that doesn’t sacrifice memory safety.
* Documentation about the borrow checker and lifetimes. The Rust book tries to treat this in an approachable manner, but I just wind up more confused; I don’t think it can be treated casually and as such I’d like to have a very thorough and detailed description of what -exactly- is going on with these language elements. If Rust’s going to be a systems language, it’s going to need to get comfortable describing what’s happening precisely.
* dyn. I love templates, static polymorphism is great. But sometimes you need runtime polymorphism. Rust treats dyn like a second class citizen.
* Arc<Box<Foo>> ugliness. Heap-allocated reference counting is a useful thing sometimes. I know Rust doesn’t prefer it, but Rust’s FTFY attitude here is annoying.
* Where are the functors??!?!? Lambdas are great and all, but I can’t create unbound trait/struct functors and then invoke them on strict references later? This is a huge limitation in runtime flexibility for application development. Boost::function and boost::bind worked with VC6 twenty years ago! When I realized Rust didn’t have functors, I became much less interested in the language.
* No function overloading. This is just silly and onerous. Rust could create sensible restrictions to avoid ambiguities and C++’s ADL/type coercion complexity but there’s nothing ambiguous about having two functions with different arity sharing the same name. The hardest problem in CS is naming things, and Rust’s lack of function overloading makes it harder still.
In general, Rust seems a whole lot less expressive than C++, and the claims that these restrictions are sacrificed for memory safety are bogus. Nothing above involves pointers and reinterpret casting and void*.
- hansonkd 4y agoI'm by no means an expert, but I don't see a lot of your "bad" points, they mostly seem like gripes about not being able to use Rust exactly as you are used to in C++ as opposed to pitfalls of learning the Rust way and doing it with Rust patterns, which would be true any time you move from one language to another.
- __jem 4y agoThis is a pretty common complaint from people who have used C++ forever and don't want to give up their design patterns when learning a new language. "Not expressive" is self-serving way to say alternatively "I can't write my OO soup" or "I don't care about safety in my C++ code", which are both evidenced in the OP's comment.
- jonstewart 4y agoI care about safety in my C++ code, thanks. What I'm saying is that all of the boogeyman stories about terrible C++ code generally don't apply to modern C++ if you work within its idioms -- memory corruption bugs are few and far between, and easy to find and fix. I've certainly seen truly awful C++ codebases, full of undefined behavior and stack and heap corruption. It's possible to write very bad unsafe C++ code; it's also possible to write safe C++ code without much difficulty. As far as design patterns: fair point that design patterns and idioms may be different in Rust but... what are they??? Fundamentally, in an application, some parts are going to read some data while another part owns it. How does that work in Rust? I haven't seen good answers yet. With procedural information processing utilities those concerns don't come into play as much, but I'd love to read about the architecture of well-functioning Rust GUI app.
- __jem 4y ago> What I'm saying is that all of the boogeyman stories about terrible C++ code generally don't apply to modern C++ if you work within its idioms -- memory corruption bugs are few and far between, and easy to find and fix. I think people are increasingly frustrated by this refrain, because there's empirical evidence that suggests otherwise. Now, it's entirely possible that you are starting greenfield projects with only super senior engineers in domains where a few safety critical bugs just don't matter, and in that case the learning curve required for memory safety just isn't worth it. That's a business decision you can make, and I wouldn't judge for a second. There are always trade-offs in engineering. However, "I don't write bugs" just isn't credible in 2023. I'm sorry if this seems uncharitable, and I appreciate that you're making a more qualified claim, but safety is not a "boogeyman." > I'd love to read about the architecture of well-functioning Rust GUI app. GUI is certainly a still developing area in Rust and has a long way to go. It's easily the weakest part of the ecosystem. That being said, it's still totally possible to build GUIs in Rust. The most common architectural pattern would be the Elm architecture, which avoids many of the issues of ownership that more traditional OO patterns introduce. I've also had a lot of success recently using immediate mode libraries, although obviously this won't work for every application.