3 ms·
I don't understand what you're saying. Are you saying that "lazy borrowing" is how the compiler works, or that it's just how you mentally model Rust for your ow
by legerdemain 3y ago
I don't understand what you're saying. Are you saying that "lazy borrowing" is how the compiler works, or that it's just how you mentally model Rust for your own convenience? There is no "lazy borrowing" in the Rust compiler, as far as I know.
You can create a mutable reference `mut1`, mutate through it, create a new mutable reference `mut2`, mutate through it, then mutate through `mut1` again. Here is an example to illustrate:
fn main() {
let mut s = String::from("1"); // create value
let mut1: &mut _ = &mut s; // create a ref mut
*mut1 = String::from("2"); // write through mut1
println!("using mut1: {mut1}"); // print mut1
let mut2: &mut _ = &mut *mut1; // create a second ref mut
*mut2 = String::from("3"); // write through mut2
println!("using mut2: {mut2}"); // print mut2
*mut1 = String::from("4"); // write through mut1 again
println!("using mut1: {mut1}"); // print mut1
}
Lifetime analysis can infer shorter lifetimes for unused refs. But creating refs in the wrong order matters even if you never use them, and not all orders are valid Rust programs. Here's a very small example that doesn't compile:
fn main() {
let mut s = String::from("1");
let mut1: &mut _ = &mut s;
let mut2: &mut _ = &mut s; // never used!
println!("Using mut1: {mut1}");
}
- saghm 3y agoThe "lazy borrowing" was just a personal mental model, not any claim about how things are implemented under the hood. That said, I think all your examples are hinging on very specific behavior from the `Deref` and `DerefMut` traits that might not apply generally. Looking at the generating MIR output[0] from your second example changed to use the deref syntax from the first one, it seems like the value of `mut1` is silently getting downgraded to `&[&str]` under the hood, presumably due to the fact that the rules for `Deref`[1] and `DerefMut`[1] allow the compiler to liberally substitute dereferences with calls to those trait methods, which crucially allows the compiler to change the result of dereferencing `&mut` to return a shared reference. This is actually almost exactly what was being suggested in the sibling comment here: https://news.ycombinator.com/item?id=39557697 https://news.ycombinator.com/item?id=39557697. [0]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=30c1c3fda19450fee4519eb49720e2a2 https://play.rust-lang.org/?version=nightly&mode=debug&editi... [1]: https://doc.rust-lang.org/std/ops/trait.Deref.html#deref-coercion https://doc.rust-lang.org/std/ops/trait.Deref.html#deref-coe... [2]: https://doc.rust-lang.org/std/ops/trait.DerefMut.html#mutable-deref-coercion https://doc.rust-lang.org/std/ops/trait.DerefMut.html#mutabl... (edited shortly after posting to rephrase without needing to use deref operator in the in-line snippets because it messed up the italics of all of the text after like this)
- legerdemain 3y agoWould it be easier to convince you if I replaced String with a type that doesn't implement Deref or DerefMut? I do wish you had tried it yourself, because I hope your goal is to learn something about Rust and not just to argue down someone on the Internet. fn main() { #[derive(Debug)] struct X(i32); let mut s = X(1); // create value let mut1: &mut _ = &mut s; // create a ref mut *mut1 = X(2); // write through mut1 println!("using mut1: {mut1:?}"); // print mut1 let mut2: &mut _ = &mut *mut1; // create a second ref mut *mut2 = X(3); // write through mut2 println!("using mut2: {mut2:?}"); // print mut2 *mut1 = X(4); // write through mut1 again println!("using mut1: {mut1:?}"); // print mut1 }
- saghm 3y ago> Would it be easier to convince you if I replaced String with a type that doesn't implement Deref or DerefMut? `&T` and `&mut T` implement Deref (and `&mut T` implements DerefMut) for all types[0]. > I do wish you had tried it yourself, because I hope your goal is to learn something about Rust and not just to argue down someone on the Internet. I'm pretty confused about the sharp turn you took here. I happen to think your explanation of what's going on in the code you posted is incorrect, and if you truly are hoping that others here are trying to learn, you'd be more successful in helping them by not acting as if anyone who doesn't think you're correct is acting in bad faith. From my perspective, you completely misread what I said about Deref in my last comment and then didn't follow the advice you're giving about trying out the change I suggested with your own code because the same error occurs with the struct you define if you don't use the deref operator[1]. I'm open to the idea that I'm wrong about `Deref` being the cause of all this, but you don't really seem to be open the idea that you might be incorrect, which comes across as fairly arrogant given that you haven't really demonstrated that you understand that I'm talking about the `Deref` implementation on the _reference_, not the underlying value,. [0]: https://doc.rust-lang.org/src/core/ops/deref.rs.html#164 https://doc.rust-lang.org/src/core/ops/deref.rs.html#164 [1]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=f830c421eccef01fb4eb2503bb47c508 https://play.rust-lang.org/?version=nightly&mode=debug&editi...