Life times variables

Why Rust compiler cant completely by himself validate lifes times?
Its not bad if compiler can do this solo when its not important.

I'm not sure what you are asking.

Can you give a specific example?

struct A { s: String } struct B { ra: &A }

That would be inference, not validation. Inference is significantly harder than validation (often impossible in its full generality). The Rust compiler can validate lifetimes ā€“ that's exactly what borrow check does. It can't infer all lifetimes, though ā€“ but it's not the compiler's fault, that'sā€¦ just how it is.

The Rust compiler does validate the lifetimes of local variables: that's the purpose of the borrow checker, to make sure that programs don't use old borrows past the end of their lifetime. So perhaps the real question is, "Why do we need to explicitly annotate lifetimes in our types and function signatures?" This is an old question, and usually two main reasons are brought up:

  • Since all lifetimes in types and function signatures are annotated, the borrow checker can be implemented with a strictly local analysis: it can check the body of one function without needing to know the bodies of the functions it calls. Otherwise, the compiler would have to have a complex caching scheme to remember the intermediate results of checks instead of repeating them for every caller.
  • Lifetimes are an important part of an API boundary. If the borrow checker could look into the code of an external library to decide that a rule is violated, then either the library would have to carefully document its borrowing patterns, or to use it you'd have to keep recompiling until it happens to work. It would also pose a massive backward compatibility hazard, since the library would be greatly limited in the ways that it could change the bodies of its functions, without making its callers start having lifetime errors. By requiring all types and functions to annotate their lifetimes upfront, it's possible to know how to cell a library's functions just by looking at its public API.

In c++ your reference cannot be empty but rust need to set reference lifes times

Rust references are not the same thing as C++ references.

Here's a good reason why this type of lifetime elision isn't done:

Yes, every reference has an associated lifetime, because it borrows a variable from somewhere in the program. If references had no lifetimes, then the borrow checker wouldn't be able to validate their lifetimes between different functions. And as I've tried to explain, granting the borrow checker that ability really wouldn't be worth the cost, because lifetime relationships are an important part of a safe API that can't be glossed over.

1 Like

Previous discussion on this topic:

An interesting aspect of global lifetime inference is that it's closely related to global type inference, which Rust doesn't have either, but it's been discussed. The reasons for (not) having one are very similar to the reasons for (not) having the other:

3 Likes

C++ doesn't enforce reference lifetimes at all, if that's what you mean. References in C++ can be left dangling, pointing to a non-existent object. Rust lifetimes protect you from that.

3 Likes

If you're wondering why Rust has strict lifetimes instead of automatically figuring out them from the code: it's because it's a deceptively difficult problem.

It seems obvious in simple cases, but it has more complex cases that are incredibly difficult and expensive to analyze, or are even provably impossible to decide at compile time. Rust chose to focus on safety, so it can't just ignore existence of the complex cases.

Handling lifetimes properly for arbitrary code in practice requires having a garbage collector, and Rust specifically chose to target programming niches where having a GC is not an acceptable trade-off.

Lifetime annotations are a compromise for safety (no edge cases with invalid lifetimes allowed), compilation speed (avoids having to trace lifetimes through the whole program and all function bodies), and run-time performance (the subset of lifetime "shapes" allowed by Rust can be handled at compile-time).

There's also a teaching/usability aspect to the lifetime syntax. Rust could try to guess lifetimes in more situations, but then when it guessed wrong, it could be even more confusing to users.


In case of structs, it's a common novice mistake to put references in structs. People complain about the terrible syntax it causes, but the real problem is not the syntax, but misunderstanding of ownership that lead them to use a wrong feature. The explosion of useless lifetime annotations then is only a symptom of another mistake, not a syntax to be fixed.

Don't put references in structs. They don't do what you think. References make structs not store the data, and instead make structs temporary scope-bound views of data stored elsewhere (typically on stack, which makes them very restricted). This is a special case that is sometimes useful, but 99% of the time it's a mistake. "Storing by reference" and "passing (ownership) by reference" in Rust is done with Box, not &.

2 Likes