3 ms·
When my Rust code successfully compiles, it usually works. Frankly in terms of user experience it's selling point #1. I could talk about the borrow checker, tra
by simias 5y ago
When my Rust code successfully compiles, it usually works. Frankly in terms of user experience it's selling point #1. I could talk about the borrow checker, trait-based generics, native build system and dependency management, performance, relative ease of writing multithreaded code etc... But thinking about it the thing I like the most about coding in Rust is how hard I can lean onto the compiler and type system to spot mistakes and let me know about them.
C++ is not even close in that respect. Duck typed generics, lack of borrow checker, lack of sync/send markers for multithreaded code, easy-to-abuse overloading (that's even abused in the standard library, so there's no escaping it), legacy cruft that springs up in unexpected places, non hygienic macros, exceptions and frankly I could go on for quite a while.
I think for some of us Rust is effectively the promised land. I learned some Lisp and Haskell but I could never really get into them seriously because despite some cool language features I just don't like paying the performance costs of a heavy runtime, dynamic typing and garbage collection. So instead it was C and C++ for better or worse. But then Rust came out and said "hey, how about having your cake and eating it too?" and I never looked back.
But of course many people don't share the same objectives. If Haskell and Common Lisp are what you consider to be your baseline I can definitely see how Rust's very strict type system would be seen as an annoyance, especially if you don't mind paying some runtime performance cost for the sake of simplicity and speed of development.
- benreesman 5y agoYou seem like someone who could write the blog post I'm looking for.
- simias 5y agoI appreciate the encouragement! Maybe I will, but first I need to write a custom blogging system. In Rust of course.
- secondcoming 5y ago> When my Rust code successfully compiles, it usually works. I think it was on a previous HN story where Rust programmers claimed that to get around borrow checker errors they just clone things. Now, the code may compile and technically be correct, but it hardly exemplifies the attention to detail normally required by a systems engineer.
- simias 5y agoI admit that I sometimes do this myself, but it's usually a last resort when I deem that a more elegant solution would probably end up being a lot more complicated and probably not a whole lot more efficient since the cloned data is only a few bytes. I use Rust on embedded devices with weak CPUs and only a hundred megs of RAM so I tend to be careful with cloning. Dealing with a lot of cloned data is also a good recipe to end up with inconsistent internal state. It may be a bit of a No True Scotsman but in my experience hanging in Rust IRC channels and similar places, the devs who tend to clone and slap `Rc<RefCell<_>>` all over the place tend to be those who come from garbage collected languages, simply because they're really not used to thinking about ownership. People who come from C, C++ and other non-GC languages are effectively already used to dealing with ownership and lifetimes, it's just that in those languages it's up to the developer to keep track of them. In terms of overall architecture I don't find that I write Rust much differently from C++, I use RAII most of the time and when that doesn't work out I'll carefully chose between cloning or some smart pointer/container. IMO Reference counting and cloning should be the exception, not the rule, and I'd go as far as saying that if you find yourself cloning and boxing data all over the place in your Rust application you're either working on a very atypical application or you're doing it somewhat wrong.
- ben-schaaf 5y ago> I don't find that I write Rust much differently from C++ Same here, though I do find myself deviating sometimes. Specifically there are cases in C++ where I could write code that makes less copies or handles data more efficiently but I don't because the approach would be more error prone. In rust these more risky approaches simply result in having more compiler errors instead of crashes or other runtime bugs.
- stouset 5y agoAs a Rust proponent I’d agree with this take 100%. There are a lot of programmers who approach new languages by trying to write in the style of their previous language. That’s not really optimal, but it can get you up and running quickly producing passable results for a wide variety of (previous, next) language pairs. Rust is not one of these languages. If you don’t try to “get” Rust and continue working across the grain, you’re going to have a rough time of things. Rust brings along an entirely new concept of explicit ownership that’s implicit in other languages, and if you simply try to push forward without internalizing those restrictions (and understanding their implications on how to structure your programs), the Rust compiler will never stop pushing back against you. While there are legitimate reasons to need Rc<RefCell<_>>, to Box things, and to clone(), the vast majority of Rust code doesn’t need to fall back on them. If you find yourself instinctively and repeatedly reaching for these as a quick workaround for borrow checker complaints, it’s going to be much better in both the long and medium term to try and understand what the compiler is trying to tell you about your overall approach to design. This is, I think, the biggest area where Rust evangelists can make some big strides. There are a lot of program designs that compile just fine in other languages but that Rust rejects (or pushes back against) for Very Good Reasons. And getting new developers over that hurdle where they understand how to internalize enough about ownership upfront that they can come up with approaches that work with the grain is a hard problem, and I’m not sure how to solve it. There’s a moment where something clicks and Rust goes from being a fight against the borrow checker to something where your designs just work out of the gate and I don’t know how to get that click to happen quicker.
- jvanderbot 5y agoLong time C++ user here. Precisely right (for me!): It is easier to get to compile because it is easier for me to express and easier to debug type / syntax problems. Once compiled, it has a very high probability of just working. I'll add that the exercise of learning rust has distilled the lessons learned in writing "good" C and C++ into a language that has few other ways of doing things. It's like someone is guiding me through good multi-threaded, memory management, and type design practices in C++ every time I work on a Rust project. This experience absolutely translates back when I'm working on C++ and C. Rust has huge potential it it can keep its libraries "upstream" of other languages. C is king of providing a one-implementation-to-many-languages (though API wrapping). If Rust can accomplish that, it'll be my language of choice. As much as I love the Unix philosophy of many interacting programs, the reality is for most systems that dynamic or static linking is how things interact.