Skip to content

Commit

Permalink
Reorganize borrowck notes and add note about re-borrowing (#2635)
Browse files Browse the repository at this point in the history
The speaker notes on the borrowck slide are a bit hard to read since
it's a big block of bulleted points. I've reorganized the notes to be a
bit easier to read by making some of the bullet points nested and by
moving some of the points to the "More to Explore" section. I've also
added a note on re-borrowing since students sometimes ask about it, and
I've added some playground links to demonstrate some of the points.
  • Loading branch information
randomPoison authored Feb 7, 2025
1 parent 386757e commit f9aca37
Showing 1 changed file with 31 additions and 17 deletions.
48 changes: 31 additions & 17 deletions src/borrowing/borrowck.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,40 @@ fn main() {
- The "outlives" rule was demonstrated previously when we first looked at
references. We review it here to show students that the borrow checking is
following a few different rules to validate borrowing.
- Note that the requirement is that conflicting references not _exist_ at the
same point. It does not matter where the reference is dereferenced.
- The above code does not compile because `a` is borrowed as mutable (through
`c`) and as immutable (through `b`) at the same time.
- Note that the intermediate reference `c` isn't necessary to trigger a borrow
conflict. Replace `c` with a direct mutation of `a` and demonstrate that this
produces a similar error. This is because direct mutation of a value
effectively creates a temporary mutable reference.
- Note that the requirement is that conflicting references not _exist_ at the
same point. It does not matter where the reference is dereferenced. Try
commenting out `*c = 20` and show that the compiler error still occurs even
if we never use `c`.
- Note that the intermediate reference `c` isn't necessary to trigger a borrow
conflict. Replace `c` with a direct mutation of `a` and demonstrate that
this produces a similar error. This is because direct mutation of a value
effectively creates a temporary mutable reference.
- Move the `println!` statement for `b` before the scope that introduces `c` to
make the code compile.
- After that change, the compiler realizes that `b` is only ever used before the
new mutable borrow of `a` through `c`. This is a feature of the borrow checker
called "non-lexical lifetimes".
- The exclusive reference constraint is quite strong. Rust uses it to ensure
that data races do not occur. Rust also _relies_ on this constraint to
optimize code. For example, a value behind a shared reference can be safely
cached in a register for the lifetime of that reference.
- The borrow checker is designed to accommodate many common patterns, such as
taking exclusive references to different fields in a struct at the same time.
But, there are some situations where it doesn't quite "get it" and this often
results in "fighting with the borrow checker."
- After that change, the compiler realizes that `b` is only ever used before
the new mutable borrow of `a` through `c`. This is a feature of the borrow
checker called "non-lexical lifetimes".

## More to Explore

- Technically multiple mutable references to a piece of data can exist at the
same time via re-borrowing. This is what allows you to pass a mutable
reference into a function without invaliding the original reference.
[This playground example][1] demonstrates that behavior.
- Rust uses the exclusive reference constraint to ensure that data races do not
occur in multi-threaded code, since only one thread can have mutable access to
a piece of data at a time.
- Rust also uses this constraint to optimize code. For example, a value behind a
shared reference can be safely cached in a register for the lifetime of that
reference.
- Fields of a struct can be borrowed independently of each other, but calling a
method on a struct will borrow the whole struct, potentially invalidating
references to individual fields. See [this playground snippet][2] for an
example of this.

</details>

[1]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8f5896878611566845fe3b0f4dc5af68
[2]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f293a31f2d4d0d31770486247c2e8437

0 comments on commit f9aca37

Please sign in to comment.