error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> src/lib.rs:4:9
|
3 | foo(x);
| ------
| | |
| | first mutable borrow occurs here
| argument requires that `*x` is borrowed for `'static`
4 | foo(x)
| ^ second mutable borrow occurs here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `example` (lib) due to 1 previous error
Another way to see this is by calling f1 twice with t without a compilation error despite the fact &mut T doesn't implement Copy.
Not sure I understand the problem with that specific example beyond the syntax errors seeing how below compiles:
It's probably possible, but it's not clear how is that related to reborrow.
Without reborrow you wouldn't be able to call f1(t: &mut Thing) if you only have t2: &mut Thing: mutable references are invariant and their lifetime couldn't be neither expanded not reduced. But reborrow turns one, single mutable reference into two: one exist in f2 and one exist in f1.
No one outside of f1 or f2 knows about that evil plot and it's valid because f1/t and f2/t are never active simultaneously.
What you talk about is some other thing: f1 and f2 have different types and that makes the whole thing much less problematic.
The story with reborrow exist to help with POLA: on one hand calling f1(t: &mut Thing) from f2(t: &mut Thing) shouldn't be possible if you follow “mutable xor shared” model, yet the mere idea that you couldn't even just simply do an empty wrapper f2 with the exact same declaration that just simply calls f1 is violating principle of least astonished pretty severely: developers who have not idea about these “egghead-invented” lifetimes and their rules would object pretty vehemently to such a language.
Because… come on, that's just stupid an wrong: if types are exactly the same then why should that be forbidden? It makes not sense whatsoever!
Adding reborrows was probably simpler than trying to convince people that such “an obvious correct” code is, somehow, wrong.
Here’s an example where I just flail. I’m trying to pass the mutable ref down the call tree. Only one is active at a time. But I’m lost in the errors that I’ve never seen before Rust…
pub struct Ctx<'s> {
pub window_state: &'s mut State
}
fn connected_to_window(&self, ctx: Ctx) {
self.for_each_child(&|ch: &dyn Controller| {
let ctx2 = Ctx {
window_state: ctx.window_state
};
ch.connected_to_window(ctx2);
// ch.connected_to_window(ctx); // Can move out of captured var
});
...
Error:
error[E0596]: cannot borrow `*ctx.window_state` as mutable, as it is a captured variable in a `Fn` closure
--> ui/src/controller.rs:86:31
|
84 | self.for_each_child(&|ch: &dyn Controller| {
| ------------------------------- in this closure
85 | let ctx2 = Ctx {
86 | window_state: ctx.window_state
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
These both need FnMut (or FnOnce). If that's not possible -- if you can't change the Fn bound indicated in the error message -- you'll need to introduce some sort of shared mutability.
What the OP is talking about is the problem that user-defined "reference-like" types cannot implement reborrowing in Rust. &mut is privileged in that regard. There's no reason why OP's Context type couldn't in principle be "reborrowed" just like its contained references individually can; it's just a missing feature. There's a project goal aiming to add a reborrow trait and the associated language support, so maybe one day…
Ah. Got it. I guess it's “curse of knowledge”: because I have deeply interned the fact that there would always be programs that are sensible, yet rejected by Rust compiler (it's simply mathematically not possible to do otherwise) the fact that there could be properties of &mut that other types couldn't recreate wasn't suprising to me: we want/need to pass &mut around often, while turning temporary borrow into a large structure shouldn't be common, thus having special rulest just for &mut makes sense.
And yes, who knows, perhaps one day someone would expand reborrow on user-defined structs, who knows?