←back to thread

177 points signa11 | 3 comments | | HN request time: 0s | source
Show context
chrismorgan ◴[] No.42161684[source]
> This means, to be a highly productive Rust programmer, you basically have to memorize the borrow checker rules, so you get it right the first time. This is stupid, because the whole point of having a type system or a borrow checker is to tell you when you get it wrong, so you don’t have to memorize how the borrow rules work.

This is completely back to front. Of course you have to internalise the rules of a borrow checker or type system to be highly productive. How can you hope to do a good job without that?

replies(2): >>42161899 #>>42162590 #
eviks ◴[] No.42161899[source]
You can do a good job by offloading that cognitive overhead to better tooling
replies(1): >>42162565 #
1. bombela ◴[] No.42162565[source]
What if Rust itself is the better tooling?
replies(1): >>42163509 #
2. audunw ◴[] No.42163509[source]
Is it just me or is everyone in this comment talking past each other, with half of them not really understanding what the article is complaining about?

My take-away was that the article concludes that Rust is NOT a good tool for working with the borrow checker. I don’t think it said that there’s anything wrong with a borrow checker, and that you shouldn’t learn the basics of how it works or how to write idiomatic Rust.

A good tool shouldn’t require you to have a perfect memory of all the rules for you to be highly productive with it. If you make mistakes it should quickly tell you so with a message that quickly lets you figure out what to change.

I think this stands in contrast with Zig where these goals is the highest priority of the language. It’s also very strict with little to no undefined behaviour. But there’s also a lot of discipline in not introducing syntax or semantics that makes it hard for the compiler/checker to give a quick pass/fail with a clear message about went wrong. You can see from the issues in GitHub that improving error messages for failures in the type system is consistently prioritised. That puts a hard constraint on Zig where they’re held back from putting too much power into the type system.

That’s not to say that Rust doesn’t prioritise being a good tool. But the semantics of borrow checking makes their job an order of magnitude more difficult here. It’s an inherent trade-off. They’ve made a huge jump in the complexity and power of the language, and it’s probably much harder to then make a tool that makes it comfortable to work with this kind of power.

Some here may find it easy to deeply understand all the rules and to write code the first time that doesn’t trip up Rust too much. But in the real world code is written by many different kinds of people with different kinds and levels of intelligence.

I’ve found this to be an important consideration when choosing languages, libraries, tools and methodologies for large teams.

One way to be a 10x programmer is to write 10x as much code as an average programmer. Another way is to make 10 other average programmers twice as efficient, and that’s clearly more scalable.

Rust may still be a good choice to make the team more productive in the long run. My point is that adopting it in a team should perhaps not be considered a trivial decision.

replies(1): >>42164950 #
3. bombela ◴[] No.42164950[source]
My short comment was a bit tongue in cheek.

> A good tool shouldn’t require you to have a perfect memory of all the rules for you to be highly productive with it. If you make mistakes it should quickly tell you so with a message that quickly lets you figure out what to change.

That's exactly what the Rust borrow checker does for me.

The borrow checker rules are quite simple conceptually.

If I own a book, I can read it, write in the margins or even destroy it. `let book: Book = Book{...}`.

I can lend this book to you exclusively `&mut Book`, you can read and write it, but not destroy it. And nobody else; including me; can even read it until you are done.

I can lend this book to you and others for reading `&Book`. We can all read it concurrently. And I must wait for everybody to be done before I can regain full ownership.

I can give you the book (passing by value). And it's now yours to do what you please. Including destroying it `drop(Book)`.

Sometimes you do want to share to many; and maybe even gate exclusive write access; at runtime. This is where Rc, Arc, Cell, RefCell and Mutex come in.

Rc and Arc destroy the book when a reference counter drops to zero. Another way to look at it, is that when the counter is 1, you have sole ownership of the book. And you can do with it what you please.

As for the runtime check for mutability, Mutex should be obvious. Cell and RefCell are similar but within a single threaded context.

And finally when you know better than the compiler, you use pointers (instead of references) and triple check your work within `unsafe` blocks.