There is another use case that I think is also important, which is when a user-defined type appears in a parameter list. Basically, I think it should be visually evident when a type has references, regardless of where it appears:
// This version makes it clear that `x` and `y`
// contain references, without having to consult
// the struct definition.
fn foo(x: Foo<'>, y: Foo<'>) { ... }
// This version, accepted today, does not.
fn foo(x: Foo, y: Foo) { ... }
I find that I rely frequently on the ability to visually scan for references and things in order to estimate whether refactorings will work, etc. For me this is an extended version of the principle that it’s good to have a (lightweight) visual indicator of when borrowing / ownership transfer are at play.
I was debating about Foo<ref> as well earlier, though I don’t think I ever floated it on the thread. It seems not entirely implausible. I was nervous because we are backing away from it in match, although I think that the too things aren’t necessarily in conflict.
Crazy thought: what if instead of writing lifetime (a term that I do not like anymore, for reasons I’ve already enumerated in this thread), we used ref to introduce named lifetimes?
struct Foo<ref a> { // new version of 'a
x: &a i32, // no need to write ' here
}
fn use_foo<ref a>(f: Foo<a>)
fn get_foo<ref a>(&a self) -> Foo<a>
Then we would be saying that this is the shorthand:
struct Foo<ref> {
x: &i32
}
fn use_foo(f: Foo<ref>)
fn get_foo(&self) -> Foo<ref>
If you really wanted to go crazy, you’d replace the & and &mut type constructors with ref :), so that we write fn get_foo(ref self) -> Foo<ref>. But this would then motivate one to introduce ref a.b.c as an expression. At that point, you have a bit of a problem because ref P patterns are … well … already taken (this tension being what motivated us to introduce ref binding mode in the first place).