Rereading the original proposal, I noticed I was getting it wrong. I thought that an annonymous lifetime would match another one, and the following would be valid:
fn foo(x: &Bar, y: Foo<'>) -> Foo<'>
But that is not the case, an annonymous lifetime is merely a marker for an elided lifetime, it can only make the syntax longer and never shorter. I had a different interpretation (which I find more useful) that an annonymous lifetime was just like any other except that it had a special syntax and didn’t have to be declared.
We could reinterpret the annonymous lifetime syntax as something I’ll call undeclared lifetimes. They would be just like explicit lifetimes but they are not declared and may appear only in fn signatures. They must be unambiguous with explicit lifetimes, for example '0, '1 could be the syntax for undeclared lifetimes.
This is how the above example would look:
// Leaving &Bar elided.
fn foo(x: &Bar, y: Foo<'0>) -> Foo<'0>
// Giving &Bar a throwaway lifetime.
fn foo(x: &'1 Bar, y: Foo<'0>) -> Foo<'0>
In comparison to parameter as lifetime:
// Parameter as lifetime.
fn foo(&self, data: &[i32]) -> Foo<'data>
// Throwaway lifetimes.
fn foo(&self, data: &'0 [i32]) -> Foo<'0>
// Parameter as lifetime cannot handle this case.
fn foo(&self, data: &[&'0 i32]) -> Foo<'0>
But most of the time we are only using '0, can we get sugar for that? Here we may repurpose the annonymous lifetime syntax to be sugar for an undeclared lifetime, possibly only when it is the only unelided lifetime in the signature, now the original example is valid:
// These could work.
fn foo(x: &Bar, y: Foo<'>) -> Foo<'>
fn foo(&self, data: &' [i32]) -> Foo<'>
impl<'a> Bar<'a> {
fn foo(&self, data: &'0 [i32]) -> Foo<'0, 'a>
}
// This style got more verbose.
fn foo(x: Foo<'0>, y: Foo<'1>)
// We probably don't want to mix things too much.
fn foo(&'0 self, data: &' [i32]) -> Foo<'0, '>
What do you think?