Why can't all lifetime be late-binding instead of a mix of early-binding and late-binding

Here's a concrete example to motivate the discussion Rust Playground.

My understanding is that the borrow checker is not happy with the following because of early-binding

fn generic_function<'a>(build: impl Fn(&'a str) -> Foo<'a>) {

The BC on the other hand is perfectly happy with the HRTB version, I think, due to late-binding of the lifetime

fn generic_function<F>(build: F)
where F: for <'c> Fn(&'c str) -> Foo<'c>  {

The question is - why can't all lifetime bindings be late? I read Niko's post Intermingled parameter lists · baby steps and 3216-closure-lifetime-binder - The Rust RFC Book but I still don't understand why the compiler can't do late lifetime binding always.

Here's the example in Niko's post

It appears that the compiler forces early lifetime binding when monomorphism takes place. But why can't it relax that constraint, stamp out different versions of the code, and bind lifetime afterwards?

1 Like

It's not impossible. I.E. it's theoretically possible to be late bound for all lifetimes, but Rust just chooses the design of early bound in some cases currently.

Whether these would be good ideas to implement is a separate question- they are only brought up to illustrate that the current rules are not necessarily set in stone and a result of "its the only way of doing this".

5 Likes