-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Consider mentioning the syntax to destructure a tuple struct #4047
Consider mentioning the syntax to destructure a tuple struct #4047
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ll start by explaining why things work the way they do, then circle back to the question of whether we should tweak the text here.
Why Things Work This Way
On the first point, the syntax without the name already means something: a “regular” tuple type:
let regular_tuple = (1, "hello", true);
let (num, str, boolean) = regular_tuple;
While Rust could choose to make that work there, and likewise for structs with named fields, the language has instead chosen to keep them distinct, in part so that the distinction is clear when reading code. You’re not wrong that the compiler definitely should know what the type is , so I can imagine adding some syntax sugar to make it nicer where it is unambiguous, but I don’t see that on the horizon any time soon!
As to the second point you make, the text actually explicitly addresses it in the paragraph preceding:
Note that the
black
andorigin
values are different types because they’re instances of different tuple structs. Each struct you define is its own type, even though the fields within the struct might have the same types. For example, a function that takes a parameter of typeColor
cannot take aPoint
as an argument, even though both types are made up of threei32
values. Otherwise, tuple struct instances are similar to tuples in that you can destructure them into their individual pieces, and you can use a.
followed by the index to access an individual value.
This is one of the reasons that this is useful: you don’t want to end up using a Color
where you mean a Point
and vice versa, because they have different semantics for those three i32
values. Consider, if the non-named form were allowed:
let (x, y, z) = black;
do_something_in_coord_space(x, y, z);
Whoops. That type-checks, but it’s a bug. And even in the case where it doesn’t type check, your compiler error could end up far away from the mistake:
struct Point(i32, i32, i32);
struct Color(u8, u8, u8);
let black = Color(0, 0, 0);
// mistake is here, because these are all u8 now
let (x, y, z) = black;
// But the type error is here
do_something_with_x_and_y(x, y);
// ^ ^
Requiring it to be a bit more explicit makes it much likelier that we get the error at the point we destructure the values.
So while Rust could make it “just work”, and some other languages do, there are tradeoffs here!
Changes to the Text
I did a quick check and we never cover this in the book, so I do think it’s worth mentioning. I don’t think we need to get into all the detail and background I just covered here, of course! I think we can also skip the “does not compile” example and just add a sentence like this to the end of the preceding paragraph:
Unlike tuples, tuple structs require you to name the type of the struct when you destructure them, because they are different types even when they have the same fields.
Let’s also go ahead and revert the changes to the listing. Thanks!
Thank you very much for the detailed explanation. That is super helpful! 😄 I adjusted the PR, but I dropped the last few words ("because they are different types even when they have the same fields") because that's already been mentioned in that same paragraph, so it felt redundant and repetitive when I put it all together. Let me know if you feel strongly otherwise, and I will re-add that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You’re welcome, and thanks for the contributin!
I would like to propose that we consider explicitly mentioning the syntax for destructing a tuple struct in the book. One thing that may be surprising to newcomers is that you need to declare the type of the struct that you are destructuring. To me, it is still not clear why this is even needed, given that the compiler should know the type of the struct that you are operating on?
Here's the error I got when I tried without the type:
This fixes it:
Funny enough, this fails:
Which means the compiler does know what it expects, but it wants the programmer to explicitly say it!