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...
Realistically unless you want to work at Jane Street or Inria (the French computer science lab where Ocaml was made), if you want to use Ocaml, it's going to be as a hobby.
The borrowchecker is what I like the least about Rust
61–70 of 459 posts
Re: The borrowchecker is what I like the least about Rust
#62>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…
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 on your arrays / vectors, then you might run into indices being use-after-free and now those SAFETY comments that previously felt pretty obvious, even trivial, may no longer be quite so safe to be around of.
I've actually written about this previously w.r.t. the borrow checker and implementing a GC system based on indices / handles. My opinion was that unless you're putting in ironclad lifetimes on your indices, all assumptions based on indices must be always checked before use.
Re: The borrowchecker is what I like the least about Rust
#63Re: The borrowchecker is what I like the least about Rust
#64Earlier quoted context omitted.
Have you tried to assure yourself that this or that piece of software (your primary text editor for example) doesn't need to be memory safe because it won't ever receive as input any data that might have been crafted by an attacker? In my experience, doing that is harder than satisfying the borrow checker.
Yes, and you can choose to use any language with a garbage collector and get the same benefit. The list of memory safe languages at your disposal is endless and they come in every flavor you can imagine.
Sometimes you can't afford that though, from web browsers to MCUs to hardware drivers to HFT.
Re: The borrowchecker is what I like the least about Rust
#65This post pretty much completely ignores the advantages of the borrow checker. I'm not talking about memory safety, which is it's original purpose. I'm talking about the fact that code that follows Rust's tree-style ownership pattern and doesn't excessively circumvent the borrow checker is more likely to be correct . I don't think that was ever the intent behind the borrow checker but it is definitely an outcome. So…
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 .
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.
Re: The borrowchecker is what I like the least about Rust
#66Earlier quoted context omitted.
Have you tried to assure yourself that this or that piece of software (your primary text editor for example) doesn't need to be memory safe because it won't ever receive as input any data that might have been crafted by an attacker? In my experience, doing that is harder than satisfying the borrow checker.
Yes, and you can choose to use any language with a garbage collector and get the same benefit. The list of memory safe languages at your disposal is endless and they come in every flavor you can imagine.
Re: The borrowchecker is what I like the least about Rust
#67Earlier quoted context omitted.
He's not ignoring them. The point of the article is that the author doesn't experience those things as concrete advantages for them. Like sure, there are advantages to those things, but the author says he doesn't feel it's worth the trouble in his experience for the sorts of code he's writing.
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."
Re: The borrowchecker is what I like the least about Rust
#68Earlier quoted context omitted.
Typescript has escape hatches so you can just say "I don't care, or don't know." With Rust, you're battling a compiler that has a very restrictive model, that you can't shut up. You will end up performing major refactors to implement what seem like trivial additions.
You can always use `Box ` to get the same result in Rust :)
Re: The borrowchecker is what I like the least about Rust
#69Earlier quoted context omitted.
Auto-deriving Copy would also mean that there needs to be an escape-hatch: eg. Vec would auto-derive Copy.
Copy is already banned for any type that directly or indirectly contains a non-Copy type, and Vec contains a `*const T`, which is not Copy.
https://doc.rust-lang.org/std/primitive.pointer.html#impl-Co...
Re: The borrowchecker is what I like the least about Rust
#70 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 a routine Rust experience. Rust forces you to pay for your technical debt up front in that area.
The other big problem is back references. Rust still lacks a good solution in that area. So often, you want A to own B, and B to be able to reference A. Rust will not allow that directly. There are three workarounds commonly used.
- Put all the items in an array and refer to them by index. Then write run-time code to manage all that. The Bevy game engine is an example of a large Rust system which does this. The trouble is that you've re-created dangling pointers, in the form of indices kept around after they are invalid. Now you have most of the problems of raw pointers. They will at least be an index to some structure of the right type, but that's all the guarantee you get. I've found bugs in that approach in Rust crates.
- Unsafe code with raw pointers. That seldom ends well. Crates which do that are almost the only time I've had to use a debugger on Rust code.
- Rc/RefCell/run-time ".borrow()". This moves all the checking to run time. It's safe, but you panic at run time if two things borrow the same item.
This is a fundamental problem in Rust. I've mentioned this before. What's needed to fix this is an analyzer that checks the scope of explicit .borrow() and .borrow_mut() calls, and determines that all scopes for the same object are disjoint. This is not too hard conceptually if all the .borrow() calls produce locally scoped results. It does mean a full call chain analysis. It's a lot like static detection of deadlock, which is a known area of research [1] but something not seen in production yet.
I've discussed this with some of the Rust developers. The problem is generics. When you call a generic, the calling code has no idea what code the generic is going to generate. You don't know what it's going to borrow. You'd have to do this static analysis after generic expansion. Rust avoids that; generics either compile for all cases, or not at all. Such restricted generic expansion avoids the huge compile error messages from hell associated with C++ template instantiation fails. Post template expansion static analysis is thus considered undesirable.
Fixing that could be done with annotation, along the lines of "this function might borrow 'foo'". That rapidly gets clunky. People hate doing transitive closure by hand. Remember Java checked exceptions.
This is a good PhD topic for somebody in programming language theory. It's a well-known hard problem for which a solution would be useful. There's no easy general fix.