4 ms·
How about the example given below by Manish? The following program will never fail. fn main() { let mut x = 0; let y = &x; println!("{}", y
by madez 10y ago
How about the example given below by Manish? The following program will never fail.
fn main() {
let mut x = 0;
let y = &x;
println!("{}", y);
x += 1;
println!("{}", x);
}
It still doesn't pass the borrow checker.
- steveklabnik 10y agoI mean, yes, I'm not saying that there aren't safe programs that the borrow checker can't know about. This is an inherent aspect of how safety works; for soundness reasons, you want to be conservative. What I do mean is, many times we have people drop by IRC and say "the borrow checker is dumb, I want to do X, and it won't let me" and the reply is something like "have you considered threading" and they go "ohhhhh I see." There was a good quote of the week about this at some point, but I can't find it right now. I don't happen to run into patterns like the above code in real Rust code, personally. That doesn't mean that they don't happen, but I'm interested in _real world_ cases where this becomes an issue. We've got a bunch of them, which is why we're pursuing non-lexical lifetimes, but it seems like for many, this is a _constant_ struggle, and I run into a NLL situation maybe once every two months. Figuring out that disconnect is very interesting to me. It matters because I'm going to be responsible for teaching it, so real examples are way better than contrived ones. Moving that focus is the point of my current re-write of these docs :)
- madez 10y agoI'm well aware that it is unreasonable to expect the compiler to accept all safe programs, hence it needs to be conservative. It must only accept code that it can prove to be safe or that is marked as unsafe (funny, maybe the keyword here should be safe, as the user vouches for the safety of the code) by the user. Your argument that for real world programs the borrow checkers conservatism does not create technical problems is completely plausible to me. The issue lies somewhere else. There is a psychological component to this. People struggle with the borrow checker, or at least they feel like they did. This is negative for rust. My point is that it would be better if it weren't trivial to write short, safe programs that are not accepted by the compiler. Where can one expect the line to be drawn? I don't know. I worked with Isabelle/HOL to formalize mathematical proofs and there I saw that we can indeed expect a computer to be reasonably clever in abstract reasoning. I'm not saying that the rust compiler is dumb, however, there is room for improvement. Thanks for your(plural) work on rust, btw.
- steveklabnik 10y agoAbsolutely, agree 100%. (I even tried to get unsafe renamed to "trusted"... that didn't work out.)
- braveo 10y agoThat's really unfortunate because I think too many people misunderstand safety in rust. The word "trust" absolutely describes safe blocks better than the word "safe" does.
- surrealize 10y agoThe first time I wanted a NLL, I did a hash lookup, matched on the option that came back, and wanted to insert into the hash in the None match arm. Since then I think they've added convenience methods for getting or inserting. I still hope that IndexAddAssign (which would have addressed my use case) becomes an overloadable operator someday. Recently I was parsing a line-oriented, whitespace delimited file and had to introduce a temporary ("line", below): let f = File::open(path)?; let reader = BufReader::new(f); for line_result in reader.lines() { let line = line_result?; let mut word_iter = line.split_whitespace(); because I think something didn't live long enough when I did line_result?.split_whitespace(). I forget exactly what the code was like before I got it past the borrow checker, though. For me, it seems like every time I dip a toe into rust I run into borrow/NLL issues right off the bat.
- steveklabnik 10y agoThank you! this is helpful. Ah, see, I'd go straight for Entry in the hash case. Which might be what you're referring to. yeah, that later one isn't NLL: it's that line_result?.split_whitespace() ^ ^ the ? will return your String, but then split_whitespace returns &strs to that String. Since it's not bound anywhere, the String would be deallocated at the end of the line, which would make the iterator dangling. NLL won't fix that.
- surrealize 10y agoThanks for following up. I found the hashmap example; it was from April 2013. I think that might have predated the Entry API. The code had ~ sigils! After failing to insert in the None arm, I tried rewriting it with find_or_insert and insert_or_update_with. Entry seems cleaner though. Thanks for the clarification about the second case not being solved by NLL. Those examples were the ones I had in my mental "code I would like the borrow checker to accept" bucket. Would Niko's proposals in that internals thread you linked ("Accepting nested method calls with an `&mut self` receiver") eliminate the need for the temporary in that second example?