Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorganize borrowck notes and add note about re-borrowing #2635

Merged
merged 2 commits into from
Feb 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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