-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Foo { .. }
pattern matches non-struct types
#3753
base: master
Are you sure you want to change the base?
RFC: Foo { .. }
pattern matches non-struct types
#3753
Conversation
a related pet peeve: you can use |
I'm against this change. A pattern is generally an inverse of an expression with the same syntax — I'm inclined to say that having the intuition of "if I can match it with a pattern, then I can create the value with a similar syntax" is good, and so breaking it is not so good. I might have had a different opinion be this a proposal for a language with a good server story. But since rust's semver story is quite bad, I don't think this small improvement can justify the special case. This is not to say we shouldn't improve rust's semver story. But in this particular case the downsides outweigh the improvement in an edge case. |
|
||
* How much code in the wild currently uses patterns like `Foo { .. }` ? | ||
* What was the original reason that the pattern `Foo { .. }` matches all | ||
structs, and not just tuple-like structs? |
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.
This is because all structures are just that, structures.
Unit structures are just a sugar for a struct with a constant:
struct Unit;
// <=>
struct Unit {}
const Unit: Unit = Unit {};
Similarly tuple structs are just a sugar for a struct with fields named as integers, a function, and a pattern (these are not expressible in surface level rust, but still):
struct Tuple(u8);
// <=>
struct Tuple { 0: u8 }
fn Tuple(_0: u8) -> Tuple { Tuple { 0: _0 } }
pattern Tuple(_0) = Tuple { 0: _0 }
So, for most intents and purposes all kinds of structs are the same.
(also this probably has a typo, I assume it should have said "not just named structs"?)
This comment was marked as off-topic.
This comment was marked as off-topic.
There is a benefit with this change other than semver compatibility - it can be useful to have an explicit type in a pattern instead of match something {
SomeStruct(SomeEnum { .. }, ....) => .., // future-proof: it's important that SomeEnum exists here
... ...instead I decided to do: match something {
SomeStruct(val, ....) => {
let _: SomeEnum = val; // future-proof: it's important that SomeEnum exists here
... |
@camsteffen IMO it would be better to have explicit syntax for annotating types in patterns, if that's the goal. |
``` | ||
|
||
To eliminate this semver hazard, this RFC proposes that the pattern `Foo { .. }` | ||
should match values of any type named `Foo`, not just structs. |
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.
This should also mention motivation for macros generating match statements where they want to verify a user-passed type.
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.
Can't a match arm like this already be generated?
ref foo_val => {
let _: &Foo = foo_val;
}
* As an alternative, we could deprecate the pattern `Foo { .. }` (either in all | ||
cases, or only in cases where `Foo` has no public fields). We could then | ||
potentially remove this pattern from the language in a future edition. |
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.
What are the use cases for using the Foo { .. }
pattern when Foo
is a struct with only private fields? If we were to start linting against that, what would we be losing?
E.g.:
//~^ WARN matching against structs with only private fields is fragile
//~| NOTE this code would break if `Foo` became an `enum` or a `union`
Special case struct patterns containing only a rest pattern (e.g.,
Foo { .. }
) so that they can match values of any type with the appropriate name, not just structs (e.g., it could match anenum Foo
value). This is done so that structs containing only private fields can be changed to other types without breaking backwards compatibility.Prior discussion on IRLO
Rendered