Skip to content

Commit 0fbf740

Browse files
committed
add nll-by-default blog post
NLL is finally going to be used by default! I'd like to highlight this achievement and in particular the hard work of a bunch of people. It also gives us a chance to hype up polonius and educate people a bit about some of the limitations of the existing borrow checker.
1 parent 4842952 commit 0fbf740

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

posts/2022-06-10-nll-by-default.md

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
layout: post
3+
title: "Non-lexical lifetimes (NLL) fully stable"
4+
author: Niko Matsakis
5+
release: true
6+
---
7+
8+
As of the Rust 1.63, the "non-lexical lifetimes" (NLL) work will be enabled by default. "But," I hear you saying, "wasn't NLL included in [Rust 2018]?" And yes, yes it was! But at that time, NLL was only enabled for Rust 2018 code, while Rust 2015 code ran in "migration mode". When in "migration mode," the compiler would run both the old *and* the new borrow checker and compare the results. This way, we could give warnings for older code that should never have compiled in the first place; we could also limit the impact of any bugs in the new code. Over time, we have limited migration mode to be closer and closer to just running the new-style borrow checker: in the next release, that process completes, and all Rust code will be checked with NLL.
9+
10+
[Rust 2018]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
11+
12+
## How does removing the old borrow checker affect users?
13+
14+
At this point, we have almost completely merged "migration mode" and "regular mode", so switching to NLL will have very little impact on the user experience. A number of diagnostics changed, mostly for the better -- [Jack Huey gives the full details in his blost post](https://jackh726.github.io/rust/2022/06/10/nll-stabilization.html).
15+
16+
## Credit where credit is due
17+
18+
The work to remove the old borrow checker has been going on for years. It's been a long, tedious, and largely thankless process. We'd like to take a moment to highlight the various people involved and make sure they are recognized for their hard work:
19+
20+
* [Jack Huey](https://github.com/jackh726/), for driving the final details of stabilization (diagnostics, reconciling differences in behavior).
21+
* [Élie Roudninski](https://github.com/marmeladema), for refactoring the diagnostics code and doing the painstaking work (along with Jack) of checking each regressed case, one by one.
22+
* [Aaron Hill](https://github.com/Aaron1011), for numerous improvements to bring NLL diagnostics up to par.
23+
* [Matthew Jasper](https://github.com/matthewjasper), for reconciling errors around higher-ranked lifetimes and other core diagnostics improvements.
24+
* [Rémy Rakic](https://github.com/lqd), for rebasing Matthew's PR as well as doing other independent diagnostics work.
25+
* [Christopher Vittal](https://github.com/chrisvittal), for removing "compare" mode (don't ask).
26+
* [Centril](https://github.com/centril), for doing a lot of early work reconciling migration mode and the regular mode.
27+
* And of course the members of the NLL working group (myself, [Felix Klock](https://github.com/pnkfelix), [Santiago Pastorino](https://github.com/spastorino), [Matthew Jasper](https://github.com/matthewjasper), [Paul Daniel Faria](https://github.com/nashenas88), [Nick Nethercote](https://github.com/nnethercote)) who delivered the feature in the first place.
28+
29+
Jack's blog post includes a [detailed narrative](https://jackh726.github.io/rust/2022/06/10/nll-stabilization.html#how-did-we-get-here) of all the work involved if you'd like more details! It's a fun read.
30+
31+
## Looking forward: what can we expect for the "borrow checker of the future"?
32+
33+
The next frontier for Rust borrow checking is taking the [polonius](https://github.com/rust-lang/polonius) project and moving it from research experiment to production code. Polonius is a next-generation version of the borrow checker that was "spun off" from the main NLL effort in 2018, as we were getting NLL ready to ship in production. It's most important contribution is fixing a known limitation of the borrow checker, demonstrated by the following example:
34+
35+
```rust=
36+
fn last_or_push<'a>(vec: &'a mut Vec<String>) -> &'a String {
37+
if let Some(s) = vec.last() { // borrows vec
38+
// returning s here forces vec to be borrowed
39+
// for the rest of the function, even though it
40+
// shouldn't have to be
41+
return s;
42+
}
43+
44+
// Because vec is borrowed, this call to vec.push gives
45+
// an error!
46+
vec.push("".to_string()); // ERROR
47+
vec.last().unwrap()
48+
}
49+
```
50+
51+
This example doesn't compile today ([try it for yourself](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=517ac32f0aab076faa32b9065783bbb4)), though there's not a good reason for that. You can often workaround the problem by editing the code to introduce a redundant if ([as shown in this example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d9b25963e83201902ecf5c02d79cbc13)), but with polonius, it will compile as is. If you'd like to learn more about how polonius (and the existing borrow checker) works[^name], you can [watch my talk from Rust Belt Rust](https://www.youtube.com/watch?v=_agDeiWek8w).
52+
53+
[^name]: Or where the name "polonius" comes from!

0 commit comments

Comments
 (0)