I wanted to expand on my answer. I think I overstated the case in my conclusions and comparisons about the “equivalence” between this borrowck-based approach and a type-based approach (even one that guarantees continuous regions). In particular, I intentionally adopted a limited and simple version of “use” (i.e., one that cannot “see through” a move, or embedding the value into a structure). Most likely, if we took a type-based approach, you would get a similar feel, but with a richer notion of “use”.
let a = &mut foo;
let b = a; // alternative: `let b = (a, );`
// is the borrow of `foo` active here?
With a type-based approach, presumably the type of
b would be equal to the type of
a (or, in the alternative case, it would be a tuple that includes
a). I think that if we wanted a richer notion of “use” like this, I’d probably pursue some kind of type-based alternative – you probably could model it with the borrowck, at least those examples, but there are a host of others where it might not work (e.g.,
let b = vec![a];).
That said, I don’t really feel that’s necessary. I think the main goal is to support the simple example of
vec.push(vec.len()), not to make a super general concept of “delayed activation” that people will use all the time. I think the simple definition I gave is also readily explainable. When you do
let x = &mut..., the next time you refer to
x (basically), it is activated. When you do
foo(&mut) or some such thing, it is as if you did
let tmp = &mut; foo(tmp), and hence it is activated. But I have to ponder it – perhaps it winds up being confusing in practice.