Skip to content
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: Or patterns, i.e Foo(Bar(x) | Baz(x)) #2535

Merged
merged 26 commits into from
Oct 7, 2018

Conversation

Centril
Copy link
Contributor

@Centril Centril commented Aug 30, 2018

πŸ–ΌοΈ Rendered

⏭ Tracking issue

πŸ“ Summary

Allow | to be arbitrarily nested within a pattern such that Some(A(0) | B(1 | 2)) becomes a valid pattern.

πŸ’– Thanks

To @Nemo157 and @joshtriplett for reviewing the draft version of this RFC.

@Centril Centril added the T-lang Relevant to the language team, which will review and decide on the RFC. label Aug 30, 2018
@Centril Centril self-assigned this Aug 30, 2018
@joshtriplett
Copy link
Member

πŸ‘ I've wanted this for a while, and I look forward to using it.

@ghost
Copy link

ghost commented Sep 2, 2018

I think a drawback is that it may be suprising with bitwise or

let x = Some(1 | 2);
match x {
    Some(1 | 2) => (), // won't happen, but intuition says it would
    _ => panic!()
}

... But I guess that it's kind of already an issue right now anyway

let x = 1 | 2;
match x {
    1 | 2 => (), // won't happen
    _ => panic!()
}

@joshtriplett
Copy link
Member

@whataloadofwhat Yeah, | already doesn't mean bitwise or in the context of patterns.


The only real choice that we do have to make is whether the new addition to the
pattern grammar should be `pat : .. | pat "|" pat ;` or if it instead should be
`pat : .. | "|"? pat "|" pat ;`. We have chosen the former for 4 reasons:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: pat ::= "|"? pat "|" pat; is definitely bad, since it would allow patterns like | | A | B | C via the interpretation | (| A | B) | C. So I'm absolutely in favour of the current plan.

@SimonSapin
Copy link
Contributor

+1 on the general goal.

What is the impact on pat fragment in macro_rules? Unlike other some other combinations forbidden by RFC 550 Macro future-proofing, | is allowed to follow a pattern today and this runs without asserting in RustΒ 1.28.0:

macro_rules! foo {
    ($a: pat) => { false };
    ($a: pat | $b: pat) => { true };
}

fn main() {
    assert!(foo!(Some(_) | None));
}

@SimonSapin
Copy link
Contributor

RFC 550’s "Edit history" section links to #1336.

@mark-i-m
Copy link
Member

mark-i-m commented Sep 5, 2018

We can and have disallowed some characters in macros before (e.g. ? in separators), but we would need to act fast.

@SimonSapin
Copy link
Contributor

β€œFast” as in before May 2015?

@durka
Copy link
Contributor

durka commented Oct 2, 2018

Was serious consideration given to avoiding breakage by requiring parentheses when doing alternation at the top level? It was not added to the alternatives or drawbacks section... and this isn't the first RFC to ignore/dismiss macro breakage. Other than that I strongly approve.

@Centril
Copy link
Contributor Author

Centril commented Oct 2, 2018

@durka

It was not added to the alternatives or drawbacks section.

It wasn't added to the alternatives because it is the proposal ;)

Finally, pat macro fragment specifiers will also match the pat<no_top_alt> production as opposed to pat<allow_top_alt>.

@durka
Copy link
Contributor

durka commented Oct 2, 2018

Oh, okay great! That should be in the guide-level docs as well, not just buried in the grammar definition.

@rfcbot rfcbot added the finished-final-comment-period The final comment period is finished for this RFC. label Oct 5, 2018
@rfcbot
Copy link
Collaborator

rfcbot commented Oct 5, 2018

The final comment period, with a disposition to merge, as per the review above, is now complete.

@rfcbot rfcbot removed the final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. label Oct 5, 2018
@Centril Centril merged commit df1ea7e into rust-lang:master Oct 7, 2018
@Centril
Copy link
Contributor Author

Centril commented Oct 7, 2018

Huzzah! This RFC has been merged!

Tracking issue: rust-lang/rust#54883

@mortarroad
Copy link

I think a drawback is that it may be suprising with bitwise or

let x = Some(1 | 2);
match x {
    Some(1 | 2) => (), // won't happen, but intuition says it would
    _ => panic!()
}

... But I guess that it's kind of already an issue right now anyway

let x = 1 | 2;
match x {
    1 | 2 => (), // won't happen
    _ => panic!()
}

I agree, and I think it's horrible. I read the release notes today, and especially the example there reads highly ambiguously:

// Before
matches!(x, Some(1) | Some(2));
// Now
matches!(x, Some(1 | 2));

It may have been ambiguous before, but now it is way worse. I'm expecting this to cause a bug or two down the line.
This is a terrible sugary addition to a language that is designed for writing robust code (we have mandatory curly braces!).
I'm kind of expecting this to be a lint for integers soon...

I don't have many issues with Rust's design, but this is just plain awful.

@RalfJung
Copy link
Member

There are many situations where the new syntax makes writing robust code a lot easier since it avoids tons of repetition. It is already used plenty of times inside the Rust compiler, for example.

But I agree that in the very special case of integer patterns, this is not great. Note however that the issue exists before this RFC already, so it's not really a problem introduced by the new syntax (even though it might be amplified). Would you like to open an issue describing the problem and possible solutions? (Discussions on merged RFCs are not going to lead anywhere, and are probably just going to get lost.)

@SimonSapin
Copy link
Contributor

Some confusion is possible at a glance, but pattern context v.s. expression context is enough to resolve it. Most expression operators are syntax errors in patterns. For example matches!(x, Some(1 + 2)) is a syntax error, it is not equivalent to matches!(x, Some(3)).

@mark-i-m
Copy link
Member

A lint for the specific case that @mortarroad pointed out seems like a good idea. Frankly, it never occurred to me that one might use a bitwise or in that context (and I do a lot of bit-twiddling). Personally, I find that nested or-patterns are major ergonomics improvement, especially when right something like a state machine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-patterns Pattern matching related proposals & ideas A-syntax Syntax related proposals & ideas A-typesystem Type system related proposals & ideas disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this RFC. T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.