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.
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.
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.
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.
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.
I strongly disagree. For example, I'm working on a project that shells out to a command line program to get a graph structure, and then computes things based on that structure. I want the code that traverses the graph to be efficient, but a handful of clones is trivial compared to opening a subprocess. In my case the clones are in the constant part of the big O.
Sometimes clones can let you have a more efficient algorithm as well. Reference counting is pervasive in async primitives, and (for very specific io-bound usecases) async can sometimes be more efficient.
It comes down to knowing your domain, althorighms, data, constraints, etc. and picking the right choice. I don't think you can say Arc is always a sign of a mediocre programmer.
I've never programmed embedded, but it makes sense that you've got strong memory constraints. One thing I like about Rust though is that there's a strong culture that just because you have to walk uphill through the snow on a tiny device doesn't mean you get to look down on those of us who get to run our code on a server.
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.