notes

Log | Files | Refs | README

non_lexical_lifetimes.md (3578B)


      1 # Non-lexical lifetimes (NLL)
      2 
      3 Non-Lexical Lifetimes (NLL) is a significant improvement to Rust's borrow
      4 checker, introduced in Rust 2018 and fully stabilised by default in Rust 1.63.
      5 It changed how the compiler reasons about _how long a reference lives_.[^8]
      6 
      7 ## The Problem: Lexical Lifetimes (Before NLL)
      8 
      9 Before NLL, a reference's lifetime lasted until the **end of its enclosing
     10 scope** (the closing `}`), regardless of whether it was actually used after a
     11 certain point. This caused the borrow checker to reject perfectly safe code:[^1]
     12 
     13 ```rust
     14 let mut data = vec![1, 2, 3];
     15 let first = &data[^0];     // immutable borrow starts here
     16 println!("{}", first);    // last actual use of `first`
     17 
     18 // OLD borrow checker: `first` still "alive" until `}`, so this fails ❌
     19 // Even though `first` is never used again!
     20 data.push(4);
     21 ```
     22 
     23 ## The Fix: NLL
     24 
     25 With NLL, the compiler tracks the **last point where a reference is actually
     26 used**, and ends its lifetime there — not at the closing brace. This is based on
     27 analysing the **control-flow graph** of your code rather than just the syntactic
     28 block structure.[^6][^1]
     29 
     30 ```rust
     31 let mut data = vec![1, 2, 3];
     32 let first = &data[^0];     // immutable borrow starts
     33 println!("{}", first);    // ✅ last use — borrow ENDS HERE (NLL)
     34 
     35 data.push(4);             // ✅ now safe to mutate
     36 ```
     37 
     38 ## Lexical vs. Non-Lexical Lifetimes
     39 
     40 |                    | Lexical Lifetimes (Old)    | Non-Lexical Lifetimes (NLL)      |
     41 | :----------------- | :------------------------- | :------------------------------- |
     42 | Lifetime ends at   | Closing `}` of scope       | Last actual use of the reference |
     43 | Based on           | Syntax tree (scope blocks) | Control-flow graph               |
     44 | Rejects safe code? | Yes, in many common cases  | Much less often                  |
     45 | Introduced         | Original Rust              | Rust 2018, stable in Rust 1.63   |
     46 
     47 ## NLL and Control Flow
     48 
     49 NLL is smart enough to handle branching logic too. A borrow is only considered
     50 "live" at a point if its value **could be used in the future** from that point.
     51 This means in conditional branches where a reference is only used in one path,
     52 it won't block mutations on the other path.[^7]
     53 
     54 ```rust
     55 let mut s = String::from("hello");
     56 
     57 let r = &s;
     58 if some_condition {
     59     println!("{r}"); // r used here in one branch
     60 }
     61 // NLL knows r MAY still be live here, so mutation below could still fail
     62 // depending on the control flow — the compiler reasons through each path
     63 ```
     64 
     65 In short, NLL makes Rust's borrow checker significantly more ergonomic without
     66 compromising any of its safety guarantees — it simply became smarter about
     67 _when_ a borrow truly ends.[^1]
     68 <span style="display:none">[^10][^2][^3][^4][^5][^9]</span>
     69 
     70 <div align="center">⁂</div>
     71 
     72 [^1]: https://oneuptime.com/blog/post/2026-01-25-non-lexical-lifetimes-rust/view
     73 
     74 [^2]: https://users.rust-lang.org/t/about-non-lexical-lifetimes/111614
     75 
     76 [^3]: https://www.reddit.com/r/rust/comments/wgxr9q/nonlexical_lifetimes_nll_fully_stable_rust_blog/
     77 
     78 [^4]: https://stackoverflow.com/questions/50251487/what-are-non-lexical-lifetimes
     79 
     80 [^5]: https://www.youtube.com/watch?v=XD-nc28-8Fw
     81 
     82 [^6]: https://rust-lang.github.io/rfcs/2094-nll.html
     83 
     84 [^7]: https://www.reddit.com/r/rust/comments/6brtsu/eli5_nonlexical_lifetimes/
     85 
     86 [^8]: https://blog.rust-lang.org/2022/08/05/nll-by-default.html
     87 
     88 [^9]: https://smallcultfollowing.com/babysteps/blog/2017/02/21/non-lexical-lifetimes-using-liveness-and-location/
     89 
     90 [^10]: https://smallcultfollowing.com/babysteps/blog/2016/04/27/non-lexical-lifetimes-introduction/