What Vale taught me about linear types, borrowing, and memory safety
verdagon.dev
verdagon.dev
I've run into this with my parser combinator library, winnow [0], and am considering switching from the nicer functional model of moving to the more imperative model of `&mut` [1].
I wrote a multithreaded reference passing implementation that runs at runtime. If you have the reference you can use it, the condition is that you have to give it back when you're finished with it.
Is this a typo? I trust the author meant `Random` by move, or are they speaking to low level behavior where moves are elided to nothing where possible (and thus looks like a borrow)
fn f(x: &mut T)
and fn f(x: T) -> T
If you wanted to avoid &mut you could pass everything “inout”.This pattern is sometimes used in Rust to avoid the limitations of mut references[1].
[1] https://doc.rust-lang.org/nomicon/lifetime-mismatch.html
If I can make a T, I can make one (call it Geoff) and then core::mem::swap the reference with a mutable reference to Geoff, then call that "inout" function on Geoff (whose actual value is now the thing I had a mutable reference to) and swap them back afterwards. But if there's no way for me to get an actual T then I can't do that, how can I call it ?
That is true, but imagine that you replaced ALL “pass by mutable reference” with the “inout” pattern. That is essentially what vale is doing. And it functionally achieves the same thing (giving temporary ownership to a function).
Otherwise, if you have a temporary value (e.g. `Default`), you can convert the former to the latter via `std::mem::replace` or `std::mem::take` (which replaces with default)
fn f1(x: &mut T) {
let y = std::mem::take(x);
*x = f2(y);
}
and you can always convert the latter to the former fn f2(mut x: T) -> T {
f1(&mut x);
return x;
}
See also the `replace_with` crate: https://docs.rs/replace_withEdited-to-add: The replace_with crate seems like it's taking the opposite approach to Aria's "Pre-pooping your pants" essay and I don't like that. It has a bunch of safety pre-requisites on functions labelled safe, which is not good Rust.
As an example, consider the index_mut function with signature
fn index_mut(&mut Vec<T>, ix: usize) -> &mut T
How do you represent this?However, this insight holds for relatively common forms of ownership, and you can see this exploited in electrolysis: https://github.com/Kha/electrolysis