What does it mean `T : 'static`?

What is the proper understanding of the restriction T : 'static ?
As I understand it means "anything implementing T should not have a reference / pointer either directly or indirectly". I am asking because I used to think that it means anything implementing T should exist during the whole lifetime of the application, but such interpretation looks wrong for me now.

--

I have found an interesting article about most common misconception related lifetimes. Maybe it will become useful for anyone else too.

3 Likes

Or the type T itself should not reference anything either directly or indirectly.

That's a common misconception. The more correct way to think is not that it should exist during the whole lifetime of the program, but that it is allowed to exist that long - i.e., there won't be any dangling references if someone holds it forever.

3 Likes

The bound T: 'a means that all lifetimes annotated on the type are larger or equal to 'a. So for example, an &'short u32 is : 'short, but not : 'long. On the other hand, a &'long u32 is both : 'short and : 'long.

In the case of : 'static, it means that all lifetimes annotated on it are 'static, so you can have types with no lifetimes annotated on it, and you can have stuff like &'static str, but nothing else.

14 Likes

In that sense I'd say the syntax is comparable (and perhaps intentionally related) to the 'long : 'short lifetime relationĀ¹, where 'long lives as long as, or longer than, 'short.

Ā¹I've seen it called the outlives-relation, though since it implies that 'long lives strictly longer than 'short I find that a somewhat unsatisfying name.

1 Like

Yeah, that's a good point. So, T<'a>: 'b is the same as 'a: 'b.

3 Likes

T can have pointer parts directly as well as indirectly (it could be tree structure with heap-allocated nodes, for example). But it needs to be owned by the T. So T may contain a Box<Inner>, Vec<Inner> or an Arc<Inner>, but not an &'a Inner unless 'a: 'static.

3 Likes

The key is to understand that is that lifetime bounds only mean something for types that contain references.

If the type T does not contain any references, then : 'static is ignored. It doesn't apply to it, it doesn't mean anything. Specifically, it won't make T live for some static lifetime. A non-reference/self-contained type like i32 or String can live for as long or as short as it needs to, regardless of lifetime annotations.

Lifetimes are only for references and types with lifetimes attached (which is usually from references inside them).

2 Likes

I don't think this is quite the best way to explain it. How I think of it is that a T: 'a bound specifies a maximum upper bound on the lifetime of any individual T object. Objects can be dropped at any point before 'a ends, but cannot live any longer than 'a. For instance, a struct containing a &'short str cannot possibly be held after 'short ends. But a struct with no references at all (or only 'static references) can be held for any length of time at all, since 'static lasts all the way to the end of the program.

EDIT: I mixed up the notation in this explanation; it describes lifetime parameters T<'a>, not lifetime bounds T: 'a.

1 Like

I have found an interesting article about most common misconception related lifetimes. Maybe it will become useful for anyone else too.

Another way to put it: T is valid for the entire program. It doesn't mean that an individual value of type T will last that long (and none might even).

But you could have, in principal, a Box which lives for the entire program, or a &'static Box<u8> because Box isnt' bound to any lifetime.

4 Likes

I find your explanation more difficult to understand, because I think it'd be correct only if by "objects can be dropped" you mean ceasing use of T in a generic context, rather than dropping of the actual object (such as releasing its heap allocation or unwinding its stack space).

And when you're talking about shortening of lifetimes, that's not quite accurate for &mut lifetimes that are invariant and can't be shortened. You can use &'a mut in a smaller scope than 'a, but you can't shorten 'a at all.

1 Like

&'a mut T is covariant over 'a (but invariant over T).

2 Likes

And also to the T: Clone syntax, since that says that T is at least Clone, but it might also be more -- such as Copy or Debug.

1 Like

Ah, my apologies, I completely mixed up the terminology. I was thinking about types with lifetime parameters, i.e., MyType<'a>, which is nearly the exact opposite of MyType: 'a. The latter is only relevant to generics, as you say.

1 Like

I thought the exclusive 'a is always invariant, but the reborrow magic makes it seem covariant.

1 Like

It is covariant.

Reborrows are a type of coercion (subtypes), possible due to the variance.

Lifetimes don't actually change, so when we say things like "can shorten a lifetime", we're always really talking about some sort of reborrow or other supertyping situation.

3 Likes