that is, where the implementing type and the returned type are the same. (Inside an impl block, Self is a type alias for the implementing type.)
Practically there's not a lot of difference between the two signatures in this simple case, since you'd usually call the function as just Foo::new() either way and let type inference take care of determining the lifetime on the returned value.
The weird thing about this one is that the 'a is unconstrained when you just call Foo::new. It's pretty weird to call <Foo<'short>>::new(...) and get a Foo<'long> back.
If you switch the lifetime generics for type generics you'll get a more useful message:
for constructors, but then I found out about Self and when I changed the return type to Self, lifetime elision failed and I had to explore the difference between the snippets I sent above. Actually this is a good follow-up question, with this snippet, Rust infers the lifetimes like the latter snippet of my original question, so wouldn't it make sense for the first snippet to be more idiomatic as it is consistent with Rust's lifetime elision?
But that does make the first/former version consistent with this maximally elided version. (Which is why I'm confused/read a contradiction.) However the elision rules were chosen to cover the most common cases -- that doesn't mean a signature with more elision is always more idiomatic.
Worth noting that for the case of lifetime parameters (≠type parameters), the one with the two distinct lifetime parameters will actually be more flexible without really that much of a hurdle. That is, given:
fn takes_constructor (
new_foo: impl for<'local> FnOnce(&'local str) -> Foo<'local>,
)
{
let local = String::from("local");
let foo = new_foo(&local);
foo.stuff();
}
then one can do takes_constructor(Foo::new) with the former snippet ('a and 'b), but not the latter (-> Self constructor). That being said, in both cases takes_constructor(|s| Foo::new(s)) shall work, obviously.