Why is the borrow checker forcing me to introduce extra variables?

The following code

struct DisjointUnionSetCost {
    parent:Vec<usize>,
    rank:Vec<usize>,
    cost:Vec<usize>
}

impl DisjointUnionSetCost {
  ...
    fn find_set(&mut self, v:usize) -> usize {
        ...
    }

    fn get_cost(&mut self, v:usize) -> usize {
        self.cost[self.find_set(v)]
    }
}

gives errors telling me that the immutable borrow of *self to access cost clashes with the mutable borrow of *self to call find_set(). Why? Should not the borrow checker understand that call to find_set(), and hence the mutable borrow of *self, completes before the array is accessed?

If I change to code of get_cost() to

    fn get_cost(&mut self, v:usize) -> usize {
        let set = self.find_set(v);
        self.cost[set]
    }

which I believe should be equivalent, then the borrow checker is happy

This is a known limitation of the current borrow-checker. Appatently, at least there’s a diagnostic being implemented that will actively suggest such an insertion of an auxiliary variable.

Edit: Hmm... I’m still reading up on this, this topic is more complex than I thought. Apparently something like v.push(v.len()) where v is a Vec<usize> does actually compile with current Rust. But some variations of it don’t, e.g. v.push((&v).len()) works while v.push((&mut v).len()) doesn’t (and neither does (&mut v).push(v.len())).

1 Like

Many thanks. Reading the answer to the bug report explains some of this behaviour, but also seems to imply that the borrow checker assumes that arguments are evaluated left to right. I confirmed this with this dummy code:

    good(dummy(&dj), &mut dj);
    bad(&mut dj, dummy(&dj));

good() compiles but bad fails. Other sources seem to say that rust does not define the order of argument evaluation. Do you know if it actually does?

AFAIK Rust does define the order of argument evaluation. Left to right. I’d be interested in what those “other sources” are.

1 Like

It looks as if evaluation order is agreed, but not yet formally documented. The bug to do this has been open for two years

1 Like