better documentation of reborrowing

Open
#788 29 comments 178 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
42/100
Issue type
Documentation
Clarity
Mostly clear
Activity status
Stale
Tech stack
rust
Domain
documentation

Research direction

Start with the Reference's raw-pointer section and its implicit-borrows section, then review the related unfinished NLL discussion in #290. Determine where mutable-reference reborrowing belongs and ensure the documentation explains the provided typed and untyped examples, including when a mutable reference is moved versus reborrowed.

Written by the indexing model from the issue text.

Description

tl;dr: Rust documentation is unclear on reborrowing, should explain details in the Reference

As it stands, there is only one mention of "reborrowing" in the Reference, in this section on raw pointers. This only refers to reborrowing pointers, and not references, which is important in understanding how Rust handles mutable references (often implicitly reborrowing them instead of moving them). There is also some documentation on implicit borrowing, but again, this is sparse and does not cover reborrowing in the context of mutable references.

A key example of the implicit borrowing which confused me is the following:

fn main() {
   	let mut x = vec![1, 2, 3];
   	let y = &mut x;
   	let z: &mut Vec<i32> = y;
   	z.push(4);
   	y.push(5);
}

This code compiles fine, and x, as expected, becomes [1, 2, 3, 4, 5]. Initially, this code was unclear to me, but I was able to understand how it worked learning about both reborrowing and non lexical lifetimes. However, along the way I became familiar with how little documentation there is on the former. Questions have come up on the topic frequently, like this Reddit post from 2016, this post from 2018 on the Rust forums, more Reddit posts from 2018 and 2019, and in this forum post from January, which I found extremely helpful. A few of the discussions in these posts reference sources to reborrowing, but the only official documentation which was available is an earlier version of the Rustonomicon. There are some instances of the author of The Rust Programming Language, such as here, here, and in https://github.com/rust-lang/rust/issues/25899, mentioning adding reborrowing to the new book, but it seems that has been abandoned since: see https://github.com/rust-lang/book/issues/2144.

This concept is counter-intuitive to beginners, as it seems to violate the idea that there can only be one mutable reference to an object in a given scope. It also raises frequent forum questions, which become an effective way to get answers, but only due to the lack of documentation. Because of this, I think that some proper documentation on reborrowing is necessary. It would explain some of the quirks of this system, as choosing whether or not to reborrow is a decision made by the compiler, and can lead to some strange compilation errors without understanding this concept. For example,

let mut x = vec![1, 2, 3];
let y = &mut x;
let z = y;

will move y into z, but substituting the last line for

let z: &mut _ = y;

will reborrow y, since the compiler has to guarantee that z is &mut T. y can be freely used after the second case, but not at all after the first case. Rust has also made some progress with reborrowing, as issues like reborrowing in match arms which failed to compile in the past now work fine, without the need to force a move. The compiler can infer when it is necessary to move a &mut instead of reborrow it, but the logic behind this decision should be made clear to the programmer so that there is a better understanding of the final product.

It seems like there was some effort to document this topic (through non-lexical lifetimes) in #290. This documentation is unfinished, potentially due to the in-progress nature of non-lexical lifetimes, but the feature is stable, which means it could accompany a discussion of reborrowing. I think reborrowing is an important enough topic to get covered in some official documentation, and if not the book, then the reference should expand upon this technique.

Dominant language
Rust
Stars
1.6k
Forks
607
Avg merge
1d 1h
Merged PRs (30d)
12

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rust-lang/reference

All issues in rust-lang/reference

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.