Skip to content

Commit b04866f

Browse files
authored
Merge pull request #1925 from mdinger/vert
Allow an optional vert at the beginning of a match branch
2 parents fdf35c1 + e64560c commit b04866f

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

text/1925-optional-match-vert.md

+257
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
- Feature Name: `match_vert_prefix`
2+
- Start Date: 2017-02-23
3+
- RFC PR: https://github.com/rust-lang/rfcs/pull/1925
4+
- Rust Issue: https://github.com/rust-lang/rust/issues/44101
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
This is a proposal for the rust grammar to support a vert `|` at the
10+
beginning of the pattern. Consider the following example:
11+
12+
```rust
13+
use E::*;
14+
15+
enum E { A, B, C, D }
16+
17+
// This is valid Rust
18+
match foo {
19+
A | B | C | D => (),
20+
}
21+
22+
// This is an example of what this proposal should allow.
23+
match foo {
24+
| A | B | C | D => (),
25+
}
26+
```
27+
28+
# Motivation
29+
[motivation]: #motivation
30+
31+
This is taking a feature which is nice about `F#` and allowing it by a
32+
straightforward extension of the current rust language. After having used
33+
this in `F#`, it seems limiting to not even support this at the language
34+
level.
35+
36+
## `F#` Context
37+
38+
In `F#`, enumerations (called `unions`) are declared in the following fashion where
39+
all of these are equivalent:
40+
41+
```F#
42+
// Normal union
43+
type IntOrBool = I of int | B of bool
44+
// For consistency, have all lines look the same
45+
type IntOrBool =
46+
| I of int
47+
| B of bool
48+
// Collapsing onto a single line is allowed
49+
type IntOrBool = | I of int | B of bool
50+
```
51+
52+
Their `match` statements adopt a similar style to this. Note that every `|` is aligned,
53+
something which is not possible with current Rust:
54+
55+
```F#
56+
match foo with
57+
| I -> ""
58+
| B -> ""
59+
```
60+
61+
## Maximizing `|` alignment
62+
63+
In Rust, about the best we can do is an inconsistent alignment with one of the
64+
following two options:
65+
66+
```rust
67+
use E::*;
68+
69+
enum E { A, B, C, D }
70+
71+
match foo {
72+
// |
73+
// V Inconsistently missing a `|`.
74+
A
75+
| B
76+
| C
77+
| D => (),
78+
}
79+
80+
match foo {
81+
A |
82+
B |
83+
C |
84+
D => (),
85+
// ^ Also inconsistent but since this is the last in the sequence, not having
86+
// | a followup vert could be considered sensible given that no more follow.
87+
}
88+
```
89+
90+
This proposal would allow the example to have the following form:
91+
92+
```rust
93+
use E::*;
94+
95+
enum E { A, B, C, D }
96+
97+
match foo {
98+
| A
99+
| B
100+
| C
101+
| D => (),
102+
// ^ Gained consistency by having a matching vert.
103+
}
104+
```
105+
106+
## Flexibility in single line matches
107+
108+
It would allow these examples which are all equivalent:
109+
110+
```rust
111+
use E::*;
112+
113+
enum E { A, B, C, D }
114+
115+
// A preceding vert
116+
match foo {
117+
| A | B | C | D => (),
118+
}
119+
120+
// A match as is currently allowed
121+
match foo {
122+
A | B | C | D => (),
123+
}
124+
```
125+
126+
> There should be no ambiguity about what either of these means. Preference
127+
between these should just come down to a choice of style.
128+
129+
## Benefits to macros
130+
131+
This benefits macros. Needs filling in.
132+
133+
## Multiple branches
134+
135+
All of these matches are equivalent, each written in a different style:
136+
137+
```rust
138+
use E::*;
139+
140+
enum E { A, B, C, D }
141+
142+
match foo {
143+
A | B => println!("Give me A | B!"),
144+
C | D => println!("Give me C | D!"),
145+
}
146+
147+
match foo {
148+
| A | B => println!("Give me A | B!"),
149+
| C | D => println!("Give me C | D!"),
150+
}
151+
152+
match foo {
153+
| A
154+
| B => println!("Give me A | B!"),
155+
| C
156+
| D => println!("Give me C | D!"),
157+
}
158+
159+
match foo {
160+
A | B =>
161+
println!("Give me A | B!"),
162+
C | D =>
163+
println!("Give me C | D!"),
164+
}
165+
```
166+
167+
## Comparing misalignment
168+
169+
```rust
170+
use E::*;
171+
172+
enum E { A, B, C }
173+
174+
match foo {
175+
| A
176+
| B => {},
177+
| C => {}
178+
// ^ Following the style above, a `|` could be placed before the first
179+
// element of every branch.
180+
181+
match value {
182+
| A
183+
| B => {},
184+
C => {}
185+
// ^ Including a `|` for the `A` but not for the `C` seems inconsistent
186+
// but hardly invalid. Branches *always* follow the `=>`. Not something
187+
// a *grammar* should be greatly concerned about.
188+
}
189+
```
190+
191+
# Detailed design
192+
[design]: #detailed-design
193+
194+
I don't know about the implementation but the grammar could be updated so that
195+
an optional `|` is allowed at the beginning. Nothing else in the grammar should
196+
need updating.
197+
198+
```text
199+
// Before
200+
match_pat : pat [ '|' pat ] * [ "if" expr ] ? ;
201+
// After
202+
match_pat : '|' ? pat [ '|' pat ] * [ "if" expr ] ? ;
203+
```
204+
205+
# How We Teach This
206+
[how-we-teach-this]: #how-we-teach-this
207+
208+
Adding examples for this are straightforward. You just include an example pointing
209+
out that leading verts are allowed. Simple examples such as below should be easy
210+
to add to all different resources.
211+
212+
```rust
213+
use Letter::*;
214+
215+
enum Letter {
216+
A,
217+
B,
218+
C,
219+
D,
220+
}
221+
222+
fn main() {
223+
let a = Letter::A;
224+
let b = Letter::B;
225+
let c = Letter::C;
226+
let d = Letter::D;
227+
228+
match a {
229+
A => "A",
230+
// Can do alternatives with a `|`.
231+
B | C | D => "B, C, or D",
232+
}
233+
234+
match b {
235+
| A => "A",
236+
// Leading `|` is allowed.
237+
| B
238+
| C
239+
| D => "B, C, or D",
240+
}
241+
}
242+
```
243+
244+
# Drawbacks
245+
[drawbacks]: #drawbacks
246+
247+
N/A
248+
249+
# Alternatives
250+
[alternatives]: #alternatives
251+
252+
N/A
253+
254+
# Unresolved questions
255+
[unresolved]: #unresolved-questions
256+
257+
N/A

0 commit comments

Comments
 (0)