Iām not in favour of this RFC (also, I donāt really like the diagrams with named blocks), because it mixes two different meanings of the word ālifetimeā:
- The lifetime of a variable. (This meaning is applicable to visualising as a named block)
- The ālifetimeā as a parameter of a reference. I think that the better term for that meaning would be borrow context (this term also donāt have an ambiguity whether ālifetimeā in āreferenceās lifetimeā means the lifetime of a variable or lifetime of the reference (see comment above by @withoutboats) (imho correct answer is neither)).
@vi0 in RFCās drawbacks lists āPossible confusion with generic lifetime parameters which are also have this style '-letterā, but i fail to understand how a parameter of a reference differs from a generic lifetime. And if it would reall differ, mixing notation for them would be really confusing.
I want to say that mixing those two meaning can help developing incorrect mental model ā which indeed happened in my case. Iāve used Rust with that incorrect mental model for more than a year, and after I understood how it all works, I had to unlearn parts of the previous knowlege.
The (wrong) mental model Iāve had was based on āthe lifetime parameters are lifetimes of variablesā, and this conclusion can be easily made by looking at such diagrams as proposed in the RFC. This model would be correct for Cyclone-like region-based lifetimes (which inspired Rust), but Rust lifetimes are a totally different beast (thatās why I prefer to call them borrow contexts).
Iād like to show a few really simple examples on how the proposed notation can be misleading:
'a {
let (x, mut y) = (1, 2);
let xref: &'a i32 = &x;
y = 3;
println!("{}", x);
}
(Letās not think about whether 'a block should cover only the referenceās lifetime or not). The example above totally fails to explain why the 'a parameter on a xref doesnāt prevent to modify y, but prevents to modify x. But you could hand-wave it away by saying "well, xref is a reference to an integer, and Rust borrows it from x, not y". But consider this:
fn foo<'a>(_: &'a mut i32, _: &'a i32) -> &'a ()
let mut x = 1;
let y = 2;
let z = 3;
let lock: '? () = foo(&mut x, &y);
// here
After the lock is stored in a variable, we canāt do anything with x, canāt modify y and can do anything with z, despite the lock being a reference to just ()! If thereās something you can put in place of '? it would be a full sentece: "x is borrowed mutably and y immutably, and their lifetimes end here and there". This is what I call borrow context. (Note that this description also fits the parameter 'a in this particular invocation of foo).
As you see, using named blocks as parameters for references works only for simple examples, and the only connection between the two meanings of ālifetimeā is that every variable in referenceās borrow context has to be alive when the reference is.
Maybe these kind of diagrams actually help beginners understand borrowing (although I think that saying āx stops to exists āØhereā©ā would be enough), but adding them to the language would be harmful. Moreover, Iād say that anywere such a diagram appears, it should be noted that itās not only not a legal Rust code, but also only a mental shortcut. While Rust prevents misuing lifetimes even with a wrong mental model, deep understanding of lifetimes/borrow contexts is really important for writing safe abstractions for unsafe code.