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

Mention that the left-hand side of an assignment is dropped #4001

Closed
MariusDoe opened this issue Aug 2, 2024 · 4 comments · Fixed by #4049
Closed

Mention that the left-hand side of an assignment is dropped #4001

MariusDoe opened this issue Aug 2, 2024 · 4 comments · Fixed by #4049

Comments

@MariusDoe
Copy link

URL to the section(s) of the book with this problem: see above

Description of the problem:

  • The book explains that a value is dropped, when its owner goes out of scope (in the Ownership Rules section of chapter 4.1), but it does not explain that they are also dropped when its owner gets assigned a different value. These are the currently listed rules:
    ### Ownership Rules
    First, let’s take a look at the ownership rules. Keep these rules in mind as we
    work through the examples that illustrate them:
    * Each value in Rust has an *owner*.
    * There can only be one owner at a time.
    * When the owner goes out of scope, the value will be dropped.
  • Chapter 15.3 explains the Drop trait (and shows the reverse drop order of multiple let bindings with some example code), but also does not mention the effect of an assignment.
  • To find out about this behavior or to find out when (if at all) values that are overwritten via assignment are dropped, one currently has to look into the reference chapter for destructors (version at issue creation), it states:

    Assignment also runs the destructor of its left-hand operand, if it's initialized.

Suggested fix:

  • In chapter 4.1, mention that a reassignment of the owner of a value also drops that value.
    For example, the last bullet point of the Ownership Rules may be replaced with (added parts marked):

    • When the owner goes out of scope or is assigned a different value, the (original) value will be dropped.

    Or another rule may be added:

    • When the owner is assigned a different value, the original value will be dropped.
  • In chapter 4.1, add an explaining example of the behavior, for example between these two paragraphs. The example might look like this:

    {
        let mut s = String::from("hello");
        // do stuff with s
        s = String::from("world"); // s gets reassigned, so the "hello" String is dropped here
        // do stuff with s
    }   // this scope is now over, and the "world" String will be dropped
  • In chapter 15.3, add an example that shows the drop behavior of an assignment, by using the CustomSmartPointer already defined in the chapter. Alternatively, extend the first example in the chapter with the assignment behavior (might be too much in a single example?).

@chriskrycho
Copy link
Contributor

I spent some time looking at and thinking about how to solve this today, but as noted in a comment on the PR I opened, I have concluded that we should not try to cover this in the book—it’s far too subtle a thing for Ch. 4, and in my judgment probably even too subtle for the discussion in Ch. 15. As I note there: the fact that it is not a thing I have ever had to think about explicitly in writing a decent bit of Rust in the last 9 years—and that I got the details wrong but have never been bitten by that is indicative that it's a fairly advanced but also a fairly niche topic. I’m going to basically punt it to the Reference and documents at a similar level.

@chriskrycho chriskrycho closed this as not planned Won't fix, can't repro, duplicate, stale Sep 30, 2024
@MariusDoe
Copy link
Author

Hey @chriskrycho, thank you for looking into this! I completely understand your point about this being a subtle thing. But I noticed that your PR discusses shadowing, not assignment to an existing variable (shadowing is interesting too, I didn't know that the original variable lives on after it was shadowed). To clarify, in this issue, I was talking about the latter. To use your example from the PR:

fn main() {
    let mut s = String::from("hello");  // let mut instead of let here
    s = String::from("ahoy");           // assignment instead of let here

    println!("{s}, world!");
}

In this case, the "hello" String does go out of scope (or gets dropped, rather) in the second line of the function body (playground).

So my question is: does your point about the subtlety apply to assignment, too? If it does, I am happy to keep this issue closed :)

@chriskrycho
Copy link
Contributor

Ah! I am going to chalk that one up to day-after-a-hard-running-race brain; I totally misremembered what you were discussing here. This is indeed much less subtle and I’ll see about adding something like that PR but with this, which I think is totally reasonable. Sorry about the confusion on my end! 😅

@chriskrycho chriskrycho reopened this Oct 1, 2024
chriskrycho added a commit that referenced this issue Oct 1, 2024
Add a short new section showing how assignment to a mutable variable
causes an existing *owned* binding to be freed immediately. Create a new
code sample and a new diagram to illustrate the behavior.

Fixes #4001.
@MariusDoe
Copy link
Author

No problem, I totally understand 😅

Thanks for creating the new PR, I'll have a look at it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants