-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Allow inferring enum variant types with _::Variant
syntax
#3167
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
Comments
You should already be able to import enum variants directly: use CompassPoint::West |
That's true, but importing the variants can cause other name clashes: struct Fahrenheit(f32);
struct Celcius(f32);
enum Temperature {
Fahrenheit(Fahrenheit),
Celcius(Celcius),
}
impl Temperature {
fn flip(self) -> Self {
match self {
Self::Fahrenheit(f) => Self::Celcius(Celcius(todo!("math"))),
Self::Celcius(f) => Self::Fahrenheit(Fahrenheit(todo!("math"))),
}
}
} If we import the variants: impl Temperature {
fn flip(self) -> Self {
use Temperature::*;
match self {
Fahrenheit(f) => Celcius(Celcius(todo!("math"))),
Celcius(f) => Fahrenheit(Fahrenheit(todo!("math"))),
}
}
}
Something like As a workaround, I sometimes rename the enum to something short: impl Temperature {
fn flip(self) -> Self {
use Temperature as E;
match self {
E::Fahrenheit(f) => E::Celcius(Celcius(todo!("math"))),
E::Celcius(f) => E::Fahrenheit(Fahrenheit(todo!("math"))),
}
}
} This proposal would allow omitting the |
Ah I think I understand better now - the |
If no significant troubles will be found with this syntax, I think this idea will eventually be implemented in Rust. It's sufficiently natural, it doesn't increase the amount of Rust grammar/syntax to remember, and in some situations it removes useless redundancy. A disadvantage is that in some cases it's less obvious for the person that reads the code what the enum is. So, as usual, common sense is required to the programmer to avoid puzzle-style coding. |
Just for reference I'm starting to write an RFC that would permit this in patterns (nb: not construction). |
@jhpratt Hi! Are you still working on that RFC? I’m willing to try to write this if nobody is doing it currently. |
This looks very convenient indeed! |
@GoldsteinE go for it! |
Sorry to be another person on this, but I have a lot of free time right now and also past RFC experience... @GoldsteinE are you still working on this or can I pick it up? Did anyone write anything down yet? |
Hi! Sorry, I too got distracted from writing this (and also I don’t have RFC experience yet). @Fishrock123 you can take it. |
Pre-RFC up on the internals forum: https://internals.rust-lang.org/t/pre-rfc-inferred-enum-types/16100 |
Circa 2020 I was in favor of this, but now I think this trades too much explicitness for too little added convenience compared to the existing option of the following: use Direction as D;
match dir {
D::North => { ... }
D::East => { ... }
D::South => { ... }
D::West => { ... }
} |
sooo....
|
Looks like you just want a syntax sugar of the following: {
use Direction::*;
match {
North => { .. }
East => { .. }
South => { .. }
West => { .. }
}
} ... and that takes us back to #2830. |
There's other places than |
@rami3l yes, indeed! |
(if it wasn't clear: I gave up on this after the very large pushback on the internals forum, maybe someone can come at it with a better argument or angle.) |
I still plan on an RFC that would permit it in pattern matching (but not construction/literals). When I brought it up on IRLO a while back there was general support behind that. |
That sounds great @jhpratt. Plus you can steal a lot of the pre-RFC text that Fishrock wrote 😁 |
Just a wild thought. What would prevent us from proposing match dir {
North => { ... }
East => { ... }
South => { ... }
West => { ... }
} without the |
I actually also mentioned this in a recent Mastodon discussion with Yosh - https://mastodon.social/@Fishrock/111817810166819135 The rest of the thread should also be visible there. Chris was thinking that this wouldn't be possible due to existing typename collision but I think there should be some way to not make that be an issue. Additionally, this is already a warning: fn main() {
let a = std::time::Duration::from_secs(1);
match a {
Duration => println!("{:?}", Duration)
}
} I'm fairly certain that the compiler should be able to just internally prefix unknown types in matches to enum variants if:
I don't really see what could go wrong there. We already know that the match has to be variants of the enum in some form if we are matching it. There could be a some trouble if the enum type is not already known somehow (maybe by way of an intermediate Am i missing something? It does not seem that complicated to just omit the enum name altogether and infer it. |
Too error-prone. If you make a typo, or remove a variant from the enum but not the match, then you'll get incorrect behaviour, because Rust would treat the corresponding branch as a catch-all pattern binding the value to a new identifier. This is already the case if try to match against constants and make a typo/ Protecting against this kind of error is one of the motivations to always write constants in ALL_CAPS, because it's easier to notice when you create a new variable instead. A major benefit of Rust's pattern matching is that you can be generally sure that the compiler has your back, catching any discrepancy between the definition and use of enum variants. If you add, remove or change any variants, the compiler will complain, making refactorings much more reliable (unless you overuse catch-all arms). Anything which decreases that reliability is thus undesirable. |
I don't think this is a very solid argument against it; as I pointed out above Rust will already emit a warning in that case, and this same problem would be present with code like: {
use MyEnum::*;
match my_enum {
Variant => {}
}
} |
To add to the previous point, rust now has a dedicated deny-by-default lint for exactly the "binding name matches a variant name" case because it's so unlikely to be what was wanted: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=145cb74ce232c7430e5368c799dd1c39
(I'm still not a fan of doing this with no syntax, though. |
Just a thought, but what if this form of syntax were to be introduced: match dir using Foo::Bar::Direction {
North => { ... }
East => { ... }
South => { ... }
West => { ... }
} where
However, this comment on #2830 brings up the very valid point of match statements that destructure composite types, and hence different (possibly conflicting) type-names. match (fruit, company) using (
fruit: Foo::Fruits,
company: Bar::Companies
) {
(Apple, Google) => { ... }
(Orange, Samsung) => { ... }
(Durian, Apple) => { ... }
_ => { ... }
} This is another reason I would prefer a keyword like I might be very wrong, but as far as I can tell, any super deep nesting would require either:
Well these are my two cents on the matter (ok, a bit more than two). Like most other programmers I dislike writing more code than I need to, but I also appreciate both explicit and strong typing, and the power that that affords match statements; thus, I feel that being able to scope a type just where you need it would be a great solution to the verbosity. This is an idea that borrows from a great many other ideas, but I would love to see something added to the language to address this, either way. Edit: I think I've made a mistake in the second example, because I'm just coming up with constructed examples, but I hope the general point still stands. |
match dir as Direction {
_::North => { .. }
_::East => { .. }
_::South => { .. }
_::West => { .. }
} |
for the actual rfc please discuss in #3444. |
is it possible infer this way? match dir as Direction {
::North => { .. }
::East => { .. }
::South => { .. }
::West => { .. }
} |
I’ve recently been bouncing between Swift and Rust and have found the shorthand
.variant
syntax to be very useful. Having something similar in Rust would be very nice to have.As initially suggested in #2830, the proposal is to allow explicitly inferring types for enum variants by using a
_::
prefix.Examples
The text was updated successfully, but these errors were encountered: