Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

After glancing through this, I can confidently say this is the “Rust, The Good Parts” I’ve been waiting for. I really appreciate the simple explanation for all “whys”.

Most folks like me that are doing application programming don’t need Rust’s full feature set. You can benefit from type safety/performance/etc even with a subset of the language.

And in doing so, you are greatly enhancing the readability and on-boarding experience for those new to Rust. This realization isn’t new, it was/is widely regarded as a best practice for C++ (readability over conciseness).



> Most folks like me that are doing application programming don’t need Rust’s full feature set. You can benefit from type safety/performance/etc even with a subset of the language.

I do think Rust suffers sometimes from guides putting all the complication upfront. When I first started playing with Rust lifetimes confused me… so I used Rc<> everywhere I’d need to use a lifetime and everything worked great. Then, later, I got to grips with how lifetimes actually work.

The vast majority of Rust applications aren’t so performance centric that a little reference counting would kill them. But you rarely see it recommended because it’s not the Rust Way.


The first thing I tell people is ".clone() it, Box it, Arc it. You can make it faster later."

Experienced devs see an Arc<RwLock<T>> and are tickled by the "obvious" performance impact, but then they try to use higher ranked lifetimes before fully internalizing the rules and get frustrated. The Rust Way there is to look at how you can reframe the problem to minimize the pain, because that pain is a symptom of an ownership web that's too complex.

If you use the wrapper types while you learn the language, it makes it easier to focus only on learning the lifetime rules, instead of trying to learn the whole language at once.


How does software get slow enough that it's one of our favorite things to complain about? There are multiple causes, of course, but I think one of them is death by a thousand cuts, that is, lots of little performance compromises that ostensibly don't matter. I don't always do everything in the optimal way, but I appreciate that Rust at least gives us the possibility of having safety without compromising speed, and I think it's good to push harder in that direction.


Here’s another way to frame the original argument:

A less performant solution in a subset of Rust will still be miles ahead of optimized Python or Ruby, while being as readable. An equivalent C++ solution on the other hand could be less readable and unsafe.

Also, limited use of borrowers is not that hard to grasp. Mutable references however make my head hurt. More so when they’re used by someone who doesn’t understand their purpose well.

One mutable reference passed down a chain of functions is okay (like a shared context/state object/db connection/etc), but more than a few make my head hurt.

You can still make logical mistakes with shared context, so in general - more pure functions = easier to spot logical mistakes (as most mutations will be concentrated in one place). And this is a general rule applicable to all programming languages.


I don't think we disagree here. I agree that not using Rc<> is the optimal position but I find myself wondering how many Rust beginners got tangled up in lifetimes, gave up and went back to a garbage collected language. I think it's fine to make an on-ramp that's a little shallower.


I'd suggest using `.clone()` over `Rc` since it'll be easier. Rc is an optimization to make `.clone()` cheap, but the downside is it makes mutability more complex.


My experience is that applications get slow when they are loaded down with bajillions of layers of unnecessary bloat.

It's not because of micro-decisions such as whether to use reference counting.


Your statements seem contradictory. "bajillions of layers of bloat" sounds like exactly the situation of "many micro-decisions" that degrade performance.


A bajillion layers of unnecessary indirection is gonna have the same consequences.


That's probably a side effect of the borrow checker and its lifetimes being the interesting new thing which is mostly unique to Rust. The counted references Rc<> and Arc<> are boring, they exist in plenty of other languages (for instance, std::shared_ptr in C++). It's the same thing with Haskell and monads: every Haskell guide is going to focus on monads.


Oh, I agree. But the result is that I often see people say "don't use Rust for general purpose programming, it's too complicated" and in my experience it's actually a great general purpose programming language. You just have to reach for the tools given to you rather than push through the hard way.


+1 this is that my understanding as well regarding Rc. I can’t recall where I read but it is advised against using Rc for “not being the Rust way”. Do you have any references in doc or code that have Rc usage I can read?


> After glancing through this, I can confidently say

Yeah ok.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: