Live data from Hacker News

The borrowchecker is what I like the least about Rust

viralinstruction.com

71–80 of 459 posts

Re: The borrowchecker is what I like the least about Rust

#71

Earlier quoted context omitted.

Yes you would need an escape hatch, but your example is wrong. Vec can't be Copy, because it has a destructor. This program fails to compile: #[derive(Clone, Copy)] struct S; impl Drop for S { fn drop(&mut self) {} } fn main() {}

Actually; I'm not sure I'm wrong. If Copy was automatically derived based on fields of a struct (without the user explicitly asking for it with `#[derive(Copy)]` that is, as the parent comment suggested the OP is asking for), then your example S and the std Vec would both automatically derive Copy. Then, implementing Drop on them would become a compile error that you would have to silence by using the escape hatch to…

What I suggested OP was asking for was:

> all types that _can_ implement `Copy` should do so automatically unless you opt out

, which was explicitly intended to exclude types with destructors, not

> types should auto-derive `Copy` based purely on an analysis of their fields.

Re: The borrowchecker is what I like the least about Rust

#72
post #52

>The first time someone gave be this advice, I had to do a double take. The Rust community's whole thing is commitment to compiler-enforced correctness, and they built the borrowchecker on the premise that humans can't be trusted to handle references manually. When the same borrowchecker makes references unworkable, their solution is to... recommend that I manually manage them, with zero safety and zero language supp…

If you start making assumptions based on indices, you can turn logical errors into memory safety errors. ie. whenever you use unsafe with the SAFETY comment above it mentioning an index, you'd better be damn sure that index is valid. This goes for not only unchecked indexing but also eg. transmuting based on a checked index into a &[u8] or such. If those indexes move in and out of your API and you do some kind of GC…

My comment was implicitly about safe Rust. Obviously if you're using `unsafe`, you have to deal with unsafety ...

Re: The borrowchecker is what I like the least about Rust

#73
I don't agree with the examples in the post. To me, they all seem to support the case that the compiler is doing the right thing and flagging potential issues. In a larger and more complex program (or a library to be used by others), it's a lot harder to reason about such things. Frankly, why should I be keeping all that in my mind when the compiler can do it for me and warn when I'm about to do something that can't verified as safe.

Of course, designing for safety is quite complex and easy to get wrong. For example, Swift's "structured concurrency" is an attempt to provide additional abstractions to try to hide some complexity around life times and synchronization... but (personally) I think the results are even more confusing and volatile.

Re: The borrowchecker is what I like the least about Rust

#75

Earlier quoted context omitted.

Yes you would need an escape hatch, but your example is wrong. Vec can't be Copy, because it has a destructor. This program fails to compile: #[derive(Clone, Copy)] struct S; impl Drop for S { fn drop(&mut self) {} } fn main() {}

Actually; I'm not sure I'm wrong. If Copy was automatically derived based on fields of a struct (without the user explicitly asking for it with `#[derive(Copy)]` that is, as the parent comment suggested the OP is asking for), then your example S and the std Vec would both automatically derive Copy. Then, implementing Drop on them would become a compile error that you would have to silence by using the escape hatch to…

So if you have some struct that you use extensively through an application and you need to extend it by adding a vector you are stuck because the change would need to touch so much code.

Re: The borrowchecker is what I like the least about Rust

#76

Earlier quoted context omitted.

Hobby language? Plenty of commercial and important software has been written in OCaml. Hell, the early versions of the Rust compiler were written in OCaml...

Maybe I’m wrong, but I only really know of Jane Street for OCaml, meanwhile FAANG all has at least some rust code. Also I would argue the rust compiler started as a hobby project

Facebook Messenger's backend was/is OCaml... React was originally written in SML, then OCaml, then whatever it is now. And a bunch of places use it for various things.

https://ocaml.org/industrial-users

Re: The borrowchecker is what I like the least about Rust

#77

Earlier quoted context omitted.

There's the practical end goal benefit of safer and more robust programs, but I think there's also the piece that pg talks about in Beating The Averages which is that learning how to cooperate with these conventions and think like there's the borrow checker there makes you a better programmer even when you return to languages that don't have it .

> makes you a better programmer If a language is bad, but you must use it, then yes learn it. But, if the borrowchecker is a source of pain in Rust, why not andmit it needs work instead of saying that “it makes you better”? I’m not going to start writing brainfuck because it makes me a better programmer.

I believe that codebases written in Rust, with borrow checking in mind, are often very readable and allow local reasoning better than most other languages. The potential hardness might not stem from "making people better programmers" but from "making programmers write better code, perhaps at the cost of some level of convenience".

Re: The borrowchecker is what I like the least about Rust

#78
post #70

One of his examples of a borrow checker excess: struct Id(u32); fn main() { let id = Id(5); let mut v = vec![id]; println!("{}", id.0); } isn't even legit in modern C++. That's just move semantics. When you move it, it's gone at the old name. He does point out two significant problems in Rust. When you need to change a program, re-doing the ownership plumbing can be quite time-consuming. Losing a few days on that is…

> The trouble is that you've re-created dangling pointers

That's true, but as a runtime mitigation, adding a generational counter (maybe only in debug builds) to allocations can catch use-after-frees.

And at least it's less likely to be a security vulnerability, unless you put sensitive information inside one of these arrays.

Re: The borrowchecker is what I like the least about Rust

#79
post #56

Earlier quoted context omitted.

One good RCE in production could alter this perception quite a bit. "The mosquito repellent is useless, I see too few mosquitos around me anyway."

The author is a bioinformatician writing scientific software, and often switching back and forth between Rust, Julia, and Python. His concerns and priorities are not the same as people doing systems-level programming.

Maybe Rust, a systems language, is just a wrong tool for bioinformatic tasks. Go, Java, Typescript, Ocaml, Scala, Haskell easily offer a spectrum from extreme simplicity to extreme expressiveness, with good performance and library support, but without needing to care about memory allocation and deallocation. (Python, if you use it as the frontend to pandas / polars, also counts.)

Re: The borrowchecker is what I like the least about Rust

#80
post #33

Earlier quoted context omitted.

I've similarly thought about building a language that compiles to Rust, but handles everything around references and borrowing and abstracts that away from the user. Then you get a language where you don't have to think about memory at all, but the resulting code "should" still be fairly fast because Rust is fast (kind of ending up in the same place as Go). I haven't written a ton of Rust so maybe my assumptions of w…

Why compile to Rust for this? Many people that build transpilation languages target C directly.

Think of Rust as a kind of kernel guaranteeing correctness of your program, the rules of which your transpiler should not have to reimplement. This may be compared to how proof assistants are able to implement all sorts of complicated simplification and resolution techniques while not endangering correctness of the generated proofs at all due to them having a small kernel that implements all of verification, and as long as that kernel is satisfied with your chain of reasoning, the processes behind its generation can be entirely disregarded.
Post reply on HN