Methods that promise not to touch some fields?

Was there a proposal for this at some point? For example, in this code below, I check for an optional, and then want to call another mutating method. To do this in current Rust, I believe I’ll need to clone the thing.

Sometimes I see advice to group fields into sub-structs. But the problem with that is that different methods need different combinations of fields, so there is not one “correct” way to partition the fields of your struct.

impl A {
    fn method1(&mut self) {
        if let Some(thing) = &self.optional_thing {
            self.method2(thing); // Not allowed...
        }
    }
    fn method2(&mut self, thing: &Thing) 
        where [I promised not to touch self.optional_thing]
    { 
        ... 
    }   
}

this has been talked about a lot (it is referred as partial borrowing), but nothing has gone past the idea stage atm.
so you should not expect anything stable in the next couple years.

a small note, the way partial borrows are usually describe though is by expliciting what they do use rather than what they don't.

to solve your problem, you may want to use inlining or free standning functions which take references to all the fields they need.

2 Likes

I’m guessing you mean manual inlining - pasting the code of method2 in method1. Or can I mark a function as inline, and the borrow checker will treat it differently?

no, sadly i do mean manual. you could make it a macro ? macros do get exapanded before borrow checking.

This is an unsolved missing feature in Rust.

  • Avoid getters/setters if you can.
  • Split objects into smaller structs with smaller groups of fields.
  • Use &self in methods that mutate, and use interior mutability like Mutex or Cell types.
  • Make methods without any self parameter, and have them take references to all fields they need individually
  • Use Option.take() to remove the object from self, call self methods with the removed object, put the object back in 'self`
9 Likes

You can access disjoint field sets using destructuring and methods like split_at_mut, but this becomes verbose and breaks for traits.

Almost all proposals for this feature wind up being pointless because they too become extremely verbose and cannot work behind traits.

There is however one proposal that avoids the extreme verbosity and works for traits:

In essence, you use algebra of higher order lifetimes to tell rustc how to infer the field groupings. A higher order lifetime 'a<'b> is just an well-defined but inferred subset of the fields in the struct on a base reference of lifetime 'b.

In practice, your trait definition just says "I want foo and bar to be callable at the same time" after which rustc checks that trait impls respect this requirement.

1 Like