-
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
Pattern synonyms #1895
Pattern synonyms #1895
Conversation
What's wrong with macros? #![feature(slice_patterns)]
type Point = i32;
#[derive(Debug)]
enum Face<'a> {
Point(&'a Point),
Line(&'a Point, &'a Point),
Polygon(&'a Point, &'a Point, &'a Point, &'a [&'a Point]),
}
macro_rules! triangle {
($a:pat, $b:pat, $c:pat) => { Face::Polygon($a, $b, $c, &[]) }
}
macro_rules! quadrilateral {
($a:pat, $b:pat, $c:pat, $d:pat) => { Face::Polygon($a, $b, $c, &[$d]) }
}
fn print_face(f: &Face) {
match *f {
triangle!(a, b, c) => { println!("triangle [{}, {}, {}]", *a, *b, *c); }
quadrilateral!(a, b, c, d) => { println!("quadrilateral [{}, {}, {}, {}]", *a, *b, *c, *d); }
_ => { println!("other stuff ({:?})", *f); }
}
}
fn main() {
print_face(&Face::Point(&1));
print_face(&Face::Line(&1, &2));
print_face(&Face::Polygon(&1, &2, &3, &[]));
print_face(&Face::Polygon(&1, &2, &3, &[&4]));
print_face(&Face::Polygon(&1, &2, &3, &[&4, &5]));
} |
Just a quick note: this proposal seems related to (but narrow than) Scala's "extractor objects". See:
@nikomatsakis and I have talked over the years about wanting something like extractors for Rust, but it's never seemed like a very high priority. I suspect that if we wanted to support something like this RFC, we'd probably want to go the full way to extractors to get broader benefits. |
@kennytm you can do it with macros, yeah. But it’s still macros, you don’t have the unification with the pattern destructing style. If you have an error, you’ll get macro stuff in the error messages. @aturon actually, I miss Haskell’s pattern synonyms – the motivation is about that. I didn’t know about extractor objects. I’ll have a look! EDIT: Ok, I read it, and it’s interesting, indeed! |
text/0000-pattern-synonyms.md
Outdated
/// A triangle. | ||
pattern Triangle(a, b, c) => Polygon(a, b, c, &[]) | ||
/// A quadrangle. | ||
pattern Quadrangle(a, b, c, d) => Polygon(a, b, c, &[d]) |
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.
Missing semicolon on this line and on the pattern definition above.
This RFC should probably address backwards compatibility issues due to introducing a new keyword One possible way is to make it contextual like |
@phaazon Can you elaborate? I'm not sure what this objection means.
This doesn't seem like a huge deal. We've accepted this cost in other areas to avoid extending the language. |
A sort of obvious extension to this RFC would be to have "pattern synonyms" in trait bodies, so you can destructure generics types. I suspect this is similar to the concept of 'extractors' in Scala. On that front, this concept seems quite related to the 'fields in traits' RFC #1546 |
@solson A macro is opaque. It would make the match face {
Point(x) => {},
triangle!(x,y z) => {}, |
Something that has always concerned me with scala's extractor objects is that they lose the ability to check exhaustiveness. I consider guaranteeing exhaustiveness to be a key attribute of Rust's match. It seems to me that pattern synonyms -- or something more transparent -- could be an improvement in that respect, though it's sad that you lose the ability to do things like use regular expressions as a pattern. In any case, my overall inclination is to postpone this RFC. My feeling is that making this sort of change doesn't strike me as a high priority right now -- I don't feel it fits into the roadmap priorities in any particular way, nor do I feel that it is a kind of "key capability" for unlocking some set of applications, though it definitely makes some things nicer. I'm a bit torn about some other aspects of the RFC. On the one hand, I appreciate it's "min-max" character -- focusing on inherent impls and "pattern aliases" means that this feels like a small extension to the language, which is good. On the other hand, that also means that some of the potential use cases that more general alternatives offer are not covered (e.g., using a regular expression as a pattern, or perhaps unifying with the trait system to make a more "enum-like" trait). I'd sort of like to have an overall vision of the ultimate extents of this feature, even if we don't want to talk all those steps at once. I think it might be good to identify other use cases besides "convenience" and the rather abstract triangle example (even if they aren't fully elaborated). As a simple example, Scala's extractor objects are often cited as a way to migrate away from an |
One last thought -- we've struggled a bit with the meaning of constants in match (basically, are they a "pattern synonym" for the value, or do they compare as a kind of value equality). This isn't directly intersecting this RFC but it feels related. |
@phaazon That macro example is no more opaque than pattern aliases. Actually, maybe less? match a {
Bar(x) => {},
Foo(x, 2) => {},
} If we had pattern aliases, these patterns might expand to the same thing or overlap in some way, but they just look like regular variants. At least with |
One concrete case I've run into is stuff like this in rustc: ty::TyRef(_, ty) | ty::TyRawPtr(ty) | ty::TyBox(ty) => {}, Which is repeated in many matches. (Although TyBox is kind of gone now.) But that would further require #1882 to make a pattern alias, and I'm not sure if a macro can expand to a match pattern with pipes right now, either. |
https://is.gd/lvSpQP produces "error: macro expansion ignores token I also feel the exhaustiveness of match blocks is an important feature, and unlike macros, extractors don't seem to have much application outside of pattern matching, so imo the motivation of this proposal would be better addressed by various improvements to macros (which are already an okay solution for this). These are examples we probably want to keep in mind for pattern/by example/declarative macros 2.0. |
I disagree with that. You shouldn’t be able to notice the difference between an alias and the type it’s aliased from. Besides declaration, you don’t have a different syntax to treat a match a {
Bar(x) => {},
Foo(x, 2) => {},
} If pattern Bar(x) => Foo(x, 2); Then it’s isomorphic to: match a {
Foo(x, 2) => {},
Foo(x, 2) => {},
} The compiler should just give you the information that |
I tend to agree. Despite my affection for Scala's extractor objects, we have much bigger fish to fry in the language right now, and the design space around this feature is non-trivial (as you point out). So while I think it'd be fine to keep exploring the space on an internals thread, I think the time isn't right for landing such an RFC. @phaazon or others in support: is there a strong argument from your perspective that such a feature supports the 2017 roadmap? |
As I find that feature an extra one, I guess it doesn’t fit the 2017 roadmap. I don’t see anything else than convenience here, but I might be wrong. I already used such a feature in a Haskell project I maintain (see this page). And as you can see, without the pattern synonyms, you can still pattern match on |
@phaazon Yes, I totally agree that a feature along these lines could be a nice convenience in some cases. It's just a question of how we spend our design bandwidth -- since if we consider such a feature, we'd probably also want to explore extractor objects etc. I think that right now we have bigger convenience/ergonomics gains to focus on, so we should revisit this later on. (You might leave a comment/link on rust-lang/rust-roadmap-2017#17 for tracking purposes.) As such, I'm formally proposing to postpone this RFC. @rfcbot fcp postpone |
Team member @aturon has proposed to postpone this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period is now complete. |
There's been no additional discussion since FCP opened, so I'm going to close this RFC as postponed. Thanks @phaazon! |
Introduce pattern synonyms, used to create new patterns we can pattern match against from real patterns (
enum
’s variants,struct
destructuring, etc.).