book icon indicating copy to clipboard operation
book copied to clipboard

Improve description of access to Struct instances when a field is moved

Open tschier opened this issue 9 months ago • 6 comments

Chapter 5.1 has this paragraph:

Note that the struct update syntax uses = like an assignment; this is because it moves the data, just as we saw in the “Variables and Data Interacting with Move” section. In this example, we can no longer use user1 as a whole after creating user2 because the String in the username field of user1 was moved into user2. If we had given user2 new String values for both email and username, and thus only used the active and sign_in_count values from user1, then user1 would still be valid after creating user2. Both active and sign_in_count are types that implement the Copy trait, so the behavior we discussed in the “Stack-Only Data: Copy” section would apply. We can still use user1.email in this example, since its value was not moved out.

As a newcomer, these three portions weren't easily reconcilable:

we can no longer use user1 as a whole

This may be read as "neither user1 itself nor any part of user1 is accessible."

Both active and sign_in_count are types that implement the Copy trait, so the behavior we discussed in the “Stack-Only Data: Copy” section would apply.

That section doesn't describe behaviour in the context of structs (i.e. that those fields are still accessible).

We can still use user1.email in this example, since its value was not moved out.

This seems to contradict the first line above, that the whole over user1 is not able to be used

I propose that the book should explicitly call out that access to user1 and its fields is not straightforward. Direct access to the user1 instance is no longer valid as one or more of its fields have been moved; but that access to any of the fields that have not been moved (because they implement Copy) is still valid.

tschier avatar Jan 21 '25 22:01 tschier

Thanks for reporting. I am not sure if the text of that section really have to be improved, but the following is really interesting:

We can still use user1.email in this example, since its value was not moved out.

I totally missed that when I read that book in October 2023. Actually, moving fields of a struct in an interesting topic in general, I never thought about that, I will have to verify that in my own Rust book.

[EDIT]

I just had a look at the book of the Brown university: https://rust-book.cs.brown.edu/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax. That explanation is a bit different and more what I remember. So my guess would be that this behavior might have changed in the last 18 months?

StefanSalewski avatar Jan 23 '25 21:01 StefanSalewski

I'm new to Rust so can't comment from experience regarding the last 18 months.

The blame on Chapter 05-01 shows this edit from 3yrs ago. In that edit the ... as a whole addition could be an attempt to explain this behaviour, in which case it wouldn't be new.

At any rate, as you say moving fields of structs, and understanding what is still valid in the enclosing struct instance is an "interesting" topic, and IMHO it's at least worth flagging the interestingness to newcomers.

tschier avatar Jan 24 '25 07:01 tschier

Sorry, I am also relative new to Rust (started in October 2023), and I am a bit confused about this topic of moving struct fields. I think I actually misunderstand it initially in the way that moving one field out of a struct would invalidate the whole struct, which seems to be wrong. I was once playing with a similar use case -- having a vector of strings, and moving one element into another variable. I think that was just an invalid operation. Moving struct fields is even more interesting. I will try to learn more about this topic and fix the description in my own book -- perhaps I should ask in the Rust forum.

A related Forum post is https://users.rust-lang.org/t/invalidation-of-struct-after-moving-one-of-its-attributes/77939 but it gives not much new information.

StefanSalewski avatar Jan 24 '25 08:01 StefanSalewski

Related to this, I'd like to discuss

Note that the struct update syntax uses = like an assignment

Is it actually referring to : in email: String::from("[email protected]"),? If they are referring to = in let user2 = User { ..., it doesn't make much sense since we need to do that regardless of whether we're using struct update syntax or not.

supervaka avatar Feb 12 '25 17:02 supervaka

I think that text refers to "let user2 = User {". The point is, that like in an assignment, data from the struct on the right of the = can be moved into the newly created struct, invalidating the struct used on the right side, which is ..user1 in the example.

In other words: The struct update construct uses = as in an ordinary assignment, and as in an ordinary struct assignment, for the struct update case, data can be moved from source to destination, fully or partly invalidating the source struct.

StefanSalewski avatar Feb 14 '25 07:02 StefanSalewski

This is definitely a tricky area! I’ve reread this paragraph multiple times, and I think it would need to be about 2–3× as long to be totally clear, but I don’t want to significantly expand parts of the book like that! @tschier the “as a whole” was a commit created in another attempt to help with this years ago, but which I only merged last year (our maintenance on this goes in waves, mostly timed with Editions!), which is why @StefanSalewski hadn’t seen it.

The approach in #4208 is better in some ways but (a) loses some of the points the original is making and (for very understandable reasons!) ends up with a lot of repetition in the phrasing. For the moment, I am going to close #4208 and go with #4246, which is a much more minimal change—basically: dropping to “as a whole” but keeping the new-ish sentence at the end of the paragraph. I don’t love that, but I think it’s as good as we’re going to get without a wholesale multi-paragraph rewrite. 😮‍💨

chriskrycho avatar Feb 26 '25 19:02 chriskrycho