Why are explicit lifetimes needed in Rust?

The other answers all have salient points (fjh’s concrete example where an explicit lifetime is needed), but are missing one key thing: why are explicit lifetimes needed when the compiler will tell you you’ve got them wrong?

This is actually the same question as “why are explicit types needed when the compiler can infer them”. A hypothetical example:

fn foo() -> _ {  
    ""
}

Of course, the compiler can see that I’m returning a &'static str, so why does the programmer have to type it?

The main reason is that while the compiler can see what your code does, it doesn’t know what your intent was.

Functions are a natural boundary to firewall the effects of changing code. If we were to allow lifetimes to be completely inspected from the code, then an innocent-looking change might affect the lifetimes, which could then cause errors in a function far away. This isn’t a hypothetical example. As I understand it, Haskell has this problem when you rely on type inference for top-level functions. Rust nipped that particular problem in the bud.

There is also an efficiency benefit to the compiler — only function signatures need to be parsed in order to verify types and lifetimes. More importantly, it has an efficiency benefit for the programmer. If we didn’t have explicit lifetimes, what does this function do:

fn foo(a: &u8, b: &u8) -> &u8

It’s impossible to tell without inspecting the source, which would go against a huge number of coding best practices.

by inferring an illegal assignment of a reference to a wider scope

Scopes are lifetimes, essentially. A bit more clearly, a lifetime 'a is a generic lifetime parameter that can be specialized with a specific scope at compile time, based on the call site.

are explicit lifetimes actually needed to prevent […] errors?

Not at all. Lifetimes are needed to prevent errors, but explicit lifetimes are needed to protect what little sanity programmers have.

Leave a Comment