What is unconstrained lifetime parameter?

The below text is at the reference.

T: 'a means that all lifetime parameters of T outlive 'a. For example, if 'a is an unconstrained lifetime parameter, then i32: 'static and &'static str: 'a are satisfied, but Vec<&'a ()>: 'static is not.

So, what is the term unconstrained lifetime parameter?

If it is no lifetime bound at all, like *T, in my understanding, it should outlive the 'static, but why &'static str: 'a are satisfied?

An unconstrained lifetime is a lifetime that doesn't have a relationship to an input lifetime. They mostly only appear in unsafe code that's working with raw pointers.

Since the lifetime has no additional constraints, it can be any lifetime. In &'static str: 'a the 'a lifetime would be required to life as long as 'static for that bound to be valid. Since it has no other constraints, that's fine.

In this case I think "unconstrained" just means "an input lifetime without a 'static bound" basically, like the 'a in fn foo<'a>(i: &'a i32) or the elided lifetime in fn bar(s: &str).

Usually lifetime parameters like 'a don't have a 'static bound -- you would just use 'static -- so in general you can consider parameters like 'a to be "some unknown lifetime". In contrast, 'static is the concrete, "valid everywhere" lifetime.

For example, if you have a fn quz<'a: 'b, 'b>(s: &'b &'a str), both 'a and 'b have bounds of some sort, but they are still not constrained to be any particular lifetimes (like 'static). They could be anything at all, so long as 'a outlives 'b. For the points about T: 'a, they are unconstrained, to use the reference's terminology.


With both 'a: 'b and T: 'a, it is common to say "'a outlives 'b" and "T outlives 'a". However, when reasoning about what lifetimes mean, I prefer to say something more like "'a is valid at least everywhere 'b is", and "T is valid at least everywhere 'a is":

  • "Outlives" can be misinterpreted as "strictly greater", but it is not; 'a: 'a
  • "T outlives 'a" can be misinterpreted to mean a value must live for all of 'a, but it's a constraint on the type as a whole, not on any particular value. I feel "validity" imparts this better than "outlives".

So let's consider the cases from the reference:

  • i32: 'static holds

    • i32 has no lifetime parameters, so trivially, all parameters outlive (are at least as long as) 'static
  • &'static str: 'a holds

    • &str has one lifetime parameter, 'static. 'static: 'x for any lifetime 'x ('static is valid everywhere; 'static outlives all lifetimes), so all the lifetime parameters of &'static str outlive 'a, no matter what 'a is
    • In English, &'static str is valid everywhere, so it's certainly valid for whatever region 'a represents
  • Vec<&'a ()>: 'static does not hold

    • Vec<T> has one type paramter
    • And here, T is &(), which has one lifetime parameter
    • So Vec<'a ()> has one lifetime parameter, 'a
    • We don't know what 'a is, so it might not be 'static -- it might not be valid everywhere -- so we can't say that 'a is valid everywhere. 'a: 'static doesn't hold
    • Since 'a: 'static doesn't hold, Vec<&'a ()>: 'static doesn't hold
    • If we have a collection of borrows, and the borrows aren't valid everywhere, then the collection isn't valid everywhere either. It's only valid where the borrows are valid.

Lifetime parameter which is not constrained.

That's different kind of unconstrained :rofl:.

I think you are confusing unconstrained lifetime and unconstrained lifetime parameter.

That's not ((unconstrained lifetime) parameter), but (unconstrained (lifetime parameter)).

Yes, English is ambiguos.

1 Like