From Stacks to Trees: A new aliasing model for Rust
1–10 of 43 posts
Re: From Stacks to Trees: A new aliasing model for Rust
#2 fn two_phase(mut x: Vec) {
let arg0 = &mut x;
let arg1 = Vec::len(&x);
Vec::push(arg0, arg1);
}
> This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this codeDoes anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow checker complaining hardcore and "getting in your way" preventing you from basically doing anything you're used to (passing around pointers in C or objects in JavaScript (even though you should be following immutable practices and not doing object mutation... most of the time))
I'm sure there's probably been discussions on how to make the borrow checker less "mean/rigid/obtuse" but silently passing something as "non mut" and it actually does "mut" stuff, I wouldn't have guessed Rust allowed that.
Edit: gah, I did not realize the function signature is (mut x), I thought it was just (x) and the mut was implied which is what I was trying to call out, apologies.
Re: From Stacks to Trees: A new aliasing model for Rust
#3fn two_phase(mut x: Vec ) { let arg0 = &mut x; let arg1 = Vec::len(&x); Vec::push(arg0, arg1); } > This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow che…
Compiler being obtuse and not being able to figure when it is safe to "break rules" is the problem. Not twisting brain of the programmer into being "safe compiler". This sounds like a Stockholm syndrome.
>"you should be following immutable practices"
No I should not. I should do what makes sense in particular situation and not bending over for some zealots trying to enforce one and the only way.
Re: From Stacks to Trees: A new aliasing model for Rust
#4fn two_phase(mut x: Vec ) { let arg0 = &mut x; let arg1 = Vec::len(&x); Vec::push(arg0, arg1); } > This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow che…
No, it's the opposite that's happening here: a mutable borrow of the vector is made, and then a non-mutable thing is done with it (getting the length), before finally mutating it (pushing).
Re: From Stacks to Trees: A new aliasing model for Rust
#5fn two_phase(mut x: Vec ) { let arg0 = &mut x; let arg1 = Vec::len(&x); Vec::push(arg0, arg1); } > This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow che…
You have ownership of a Vec, you get its length, then you push to it through a mutable reference; nothing evil happens here except the order of the statements (which is an implementation detail that people might not think about when writing the short form x.push(x.len())). The code above is perfectly safe if written in C, which is why the borrow checker was extended to also allow it in Rust. You could make the argument that simpler borrow checker rules lead to a simpler mental model. The counterargument (that won in the end) is that "if it's safe, the borrow checker allows it" is a mental model worth pursuing.
Re: From Stacks to Trees: A new aliasing model for Rust
#6fn two_phase(mut x: Vec ) { let arg0 = &mut x; let arg1 = Vec::len(&x); Vec::push(arg0, arg1); } > This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow che…
fn two_phase(mut x: Vec) {
x.push(x.len());
}
This should clearly be accepted (this is self evident in my opinion); if you need to jump through loops to write code like this then the language is too restrictive to write normal code.The standard implementation of Rust does indeed accept this, and there is no soundness hole here.
The existing semantics for aliasing and borrowing from MPI (Stacked Borrows) don’t allow this, which means the semantics are overly restrictive; we want this to be accepted.
This work “fixes” this issue by extending the semantics to admit the behaviour exhibited by the standard implementation.
The rules for the borrow checker are not fully formalised and to some extent the rustc implementation is the specification; formalising the rules (i.e. RustBelt, Stacked Borrows, etc.) is important, but we don’t want to formalise something that is strictly more restrictive than the reference implementation, especially if there’s no soundness hole.
Re: From Stacks to Trees: A new aliasing model for Rust
#7fn two_phase(mut x: Vec ) { let arg0 = &mut x; let arg1 = Vec::len(&x); Vec::push(arg0, arg1); } > This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow che…
I’ve worked in OOP languages, functional languages, and dynamic languages but all of them were essentially garbage collected, so having to keep track in my head of how data ownership is managed is a big learning curve.
Re: From Stacks to Trees: A new aliasing model for Rust
#8fn two_phase(mut x: Vec ) { let arg0 = &mut x; let arg1 = Vec::len(&x); Vec::push(arg0, arg1); } > This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow che…
I’ve been learning rust and I spend the vast majority of my time dealing with lifetimes and borrow checking. Common ways in used to doing things simply don’t work in rust and a lot of effort has to go into keeping track of how and where data is used. I’ve worked in OOP languages, functional languages, and dynamic languages but all of them were essentially garbage collected, so having to keep track in my head of how d…
I can outsource this to the compiler and if I get it wrong the program won’t compile.
In c++ you still need to do all the same tracking and management if you want safe and correct programs, but you don’t get nearly as much help from the compiler if you make a mistake.
Re: From Stacks to Trees: A new aliasing model for Rust
#9Re: From Stacks to Trees: A new aliasing model for Rust
#10fn two_phase(mut x: Vec ) { let arg0 = &mut x; let arg1 = Vec::len(&x); Vec::push(arg0, arg1); } > This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow che…
>"Does anybody else wish the compiler wouldn't" Compiler being obtuse and not being able to figure when it is safe to "break rules" is the problem. Not twisting brain of the programmer into being "safe compiler". This sounds like a Stockholm syndrome. >"you should be following immutable practices" No I should not. I should do what makes sense in particular situation and not bending over for some zealots trying to enf…
I'm not a rust user myself, but I'm guessing from all the references to raw pointers that a lot of the code referenced here is actually not idiomatic for all but small snippets of high perf code, so maybe the complexity is not going to affect too many people.