From dfc2e5fe32bd01e9d65be32570953e8586e3d6e3 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sun, 10 Jul 2022 20:41:10 +0100 Subject: [PATCH 1/7] start doc --- text/0000-postfix-match.md | 272 +++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 text/0000-postfix-match.md diff --git a/text/0000-postfix-match.md b/text/0000-postfix-match.md new file mode 100644 index 00000000000..564ae0132f3 --- /dev/null +++ b/text/0000-postfix-match.md @@ -0,0 +1,272 @@ +- Feature Name: `postfix-match` +- Start Date: 2022-07-10 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +An alternative postfix syntax for match expressions that allows for interspercing match statements with function chains + +```rust +foo.bar().baz.match { + _ => {} +} +``` + +as syntax sugar for + +```rust +match foo.bar().baz { + _ => {} +} +``` + +# Motivation +[motivation]: #motivation + +Forever we hear the complaints of fresh rustaceans learning about option/result +method chaining being [very surprised by the ordering](https://github.com/rust-lang/rfcs/issues/1025) of the methods like +[`map_or_else`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_or_else). + +This RFC proposes deprecating some of these methods for a slightly more verbose but likely +more readable versions using match statements. + +In order to keep the spirit of method chaining, the core of this proposal is allowing +match to be written in a postfix form. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +`match expressions` are how one would normally deal with the values +of an enum type (eg `Option`, `Result`, etc.) by pattern matching on each +variant. Some powerful techniques like pattern binding, nested patterns and or patterns +allow for some versatile and concise, but still fairly readable syntax for dealing +with these types. + +Rust often features functional approachs to lots of problems. For instance, +it's very common to have chains of `map`, `and_then`, `ok_or`, `unwrap` +to process some `Option` or `Result` type in a pipeline, rather than continously reassigning to new variable bindings. + +```rust +let x = Some(42); +let magic_number = x.map(|x| x * 5) + .and_then(NonZeroI32::new) + .ok_or_else("5x was zero") + .unwrap(); +``` + +Some of these provided method chains are fairly readable, like the ones presented above, +but sometimes the desire to use long method chains is met with unweildy hacks or awkward function arguments. + +```rust +let x = Some("crustaceans"); +x.and_then(|x| (!x.is_empty()).then(x)) // None if x is an empty string + .map_or_else( + || "Ferris", // default + |x| &x[1..], // remove first letter + ); +``` + +These can be re-written using postfix match to be much more self-documenting + +```rust +x.match { + Some("") | None => None + x @ Some(_) => x +}.match { + Some(x) => &x[1..], + None => "Ferris", +}; + +// or even just + +x.match { + Some("") | None => "Ferris" + x @ Some(_) => &x[1..] +}; +``` + +While this example ended up being a single match, and is near-equivalent to the `match x {}` form, often these option chains can get quite long, especially when interspersed with `?`, `.await` and other forms of postfix syntax we already make heavy use of. + +you could imagine that this `x` would be replaced with + +```rust +context.client + .post("https://example.com/crabs") + .body("favourite crab?") + .send() + .await? + .json::>() + .await? + .as_ref() +``` + +```rust +// prefix match +match context.client + .post("https://example.com/crabs") + .body("favourite crab?") + .send() + .await? + .json::>() + .await? + .as_ref() +{ + Some("") | None => "Ferris" + x @ Some(_) => &x[1..] +}; + +// postfix match +context.client + .post("https://example.com/crabs") + .body("favourite crab?") + .send() + .await? + .json::>() + .await? + .as_ref() + .match { + Some("") | None => "Ferris" + x @ Some(_) => &x[1..] + }; +``` + +While it's a matter of taste, the postfix form is much easier to parse +in terms of the flow of data. Having to jump back out to the beginning of +the expression to see the `match` keyword to know what the new expression context is +can be difficult to read. + +While I am not at liberty to share the codebase, the former is equivalent to something +I see on some of our codebases at work. + +## tap (pipelines) + +While not the intended use of this proposal, [tap](https://crates.io/crates/tap) is a popular crate to allow more advanced pipeline operations. + +```rust +let val = original_value + .pipe(first) + .pipe(|v| second(v, another_arg)) + .pipe(third) + .pipe(|v| last(v, another_arg)); +``` + +This can be written similarly using our postfix match: + +```rust +let val = original_value + .match { v => first(v) } + .match { v => second(v, another_arg) } + .match { v => third(v) } + .match { v => last(v, another_arg) }; +``` + +This avoids the need for a new dedicated pipeline operator or syntax. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +This is the technical portion of the RFC. Explain the design in sufficient detail that: + +- Its interaction with other features is clear. +- It is reasonably clear how the feature would be implemented. +- Corner cases are dissected by example. + +The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. + +# Drawbacks +[drawbacks]: #drawbacks + +Having multiple forms of match could be confusing. However, I believe +that most issues could be resolved if clippy would detect uses of + +```rust +x.match {} +``` + +when the desugared + +```rust +match x {} +``` + +would fit on a single line after being rustfmt. The opposite could +also be true - if the scrutinee spans multiple lines, it should be made into +a postfix form. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +## Rationale + +The core rationale is that a lot of these method chain functions are designed to +avoid using bulky match statements that ruin the flow. + +Rather than keep adding more of these methods to suit the needs, we should +make the language more flexible such that match statements aren't a hindrance. + +## Alternatives + +[postfix macros](https://github.com/rust-lang/rfcs/pull/2442) have been an idea for many years now. If they were to land, this feature +could easily be implemented as a macro (bikeshedding on postfix macro syntax): + +```rust +macro match_! ( + postfix { $( + $arm:pat => $body:expr, + )+ } => { + match $self { $( + $arm => $body, + )+ } + } +) +``` + +However, after years of discussion and hundreds of thumbs-ups, it feels like we're +still not close to agreeing on syntax or behaviour. + +# Prior art +[prior-art]: #prior-art + +Discuss prior art, both the good and the bad, in relation to this proposal. +A few examples of what this can include are: + +- For language, library, cargo, tools, and compiler proposals: Does this feature exist in other programming languages and what experience have their community had? +- For community proposals: Is this done by some other community and what were their experiences with it? +- For other teams: What lessons can we learn from what other communities have done here? +- Papers: Are there any published papers or great posts that discuss this? If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. + +This section is intended to encourage you as an author to think about the lessons from other languages, provide readers of your RFC with a fuller picture. +If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or if it is an adaptation from other languages. + +Note that while precedent set by other languages is some motivation, it does not on its own motivate an RFC. +Please also take into consideration that rust sometimes intentionally diverges from common language features. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +- What parts of the design do you expect to resolve through the RFC process before this gets merged? +- What parts of the design do you expect to resolve through the implementation of this feature before stabilization? +- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? + +# Future possibilities +[future-possibilities]: #future-possibilities + +Think about what the natural extension and evolution of your proposal would +be and how it would affect the language and project as a whole in a holistic +way. Try to use this section as a tool to more fully consider all possible +interactions with the project and language in your proposal. +Also consider how this all fits into the roadmap for the project +and of the relevant sub-team. + +This is also a good place to "dump ideas", if they are out of scope for the +RFC you are writing but otherwise related. + +If you have tried and cannot think of any future possibilities, +you may simply state that you cannot think of anything. + +Note that having something written down in the future-possibilities section +is not a reason to accept the current or a future RFC; such notes should be +in the section on motivation or rationale in this or subsequent RFCs. +The section merely provides additional information. From b13f6145b0418533966a649d4e48e46c91d431a5 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sun, 10 Jul 2022 20:56:13 +0100 Subject: [PATCH 2/7] comment on lifetime extension --- text/0000-postfix-match.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/text/0000-postfix-match.md b/text/0000-postfix-match.md index 564ae0132f3..60227049927 100644 --- a/text/0000-postfix-match.md +++ b/text/0000-postfix-match.md @@ -246,9 +246,11 @@ Please also take into consideration that rust sometimes intentionally diverges f # Unresolved questions [unresolved-questions]: #unresolved-questions -- What parts of the design do you expect to resolve through the RFC process before this gets merged? -- What parts of the design do you expect to resolve through the implementation of this feature before stabilization? -- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? +## Lifetime extension + +Method call chains will not lifetime extend their arguments. Match statements, however, +are notorious for having lifetime extension. It is currently unclear if promoting these +usecases of match would cause more [subtle bugs](https://fasterthanli.me/articles/a-rust-match-made-in-hell#my-actual-bug), or if it's negligable # Future possibilities [future-possibilities]: #future-possibilities From e5c4fde23aa9c5fee32d39f93799cf5e6c2bdac1 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Tue, 19 Jul 2022 11:04:22 +0100 Subject: [PATCH 3/7] edit --- text/0000-postfix-match.md | 98 +++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/text/0000-postfix-match.md b/text/0000-postfix-match.md index 60227049927..bb031760bf5 100644 --- a/text/0000-postfix-match.md +++ b/text/0000-postfix-match.md @@ -25,15 +25,17 @@ match foo.bar().baz { # Motivation [motivation]: #motivation +Method chaining is something rust users do a lot to provide a nice +flow of data from left-to-right/top-to-bottom which promotes a very natural reading order +of the code. + +Sometimes, these method chains can become quite terse for the sake of composability + Forever we hear the complaints of fresh rustaceans learning about option/result method chaining being [very surprised by the ordering](https://github.com/rust-lang/rfcs/issues/1025) of the methods like [`map_or_else`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_or_else). -This RFC proposes deprecating some of these methods for a slightly more verbose but likely -more readable versions using match statements. - -In order to keep the spirit of method chaining, the core of this proposal is allowing -match to be written in a postfix form. +This RFC proposes promoting the use of match statements by supporting postfix-match, reducing the use of some of these methods terse and potentially confusing method chains. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -52,7 +54,7 @@ to process some `Option` or `Result` type in a pipeline, rather than continously let x = Some(42); let magic_number = x.map(|x| x * 5) .and_then(NonZeroI32::new) - .ok_or_else("5x was zero") + .ok_or("5x was zero") .unwrap(); ``` @@ -164,16 +166,57 @@ let val = original_value This avoids the need for a new dedicated pipeline operator or syntax. +### into + +Occasionally I've bumped into the difficulty of using `Into` in a postfix setting. +The tap crate also provides a `Conv` trait to convert in a method chain using turbofish. + +```rust +let upper = "hello, world" + .conv::() + .tap_mut(|s| s.make_ascii_uppercase()); +``` + +This can also be emulated with postfix-match + +```rust +let upper = "hello, world" + .match { s => String::from(s) } + .match { mut s => { s.make_ascii_uppercase(); s } } +``` + +## async support + +One thing of note is that in option chains you cannot use futures unless you use adapters +like [`OptionFuture`](https://docs.rs/futures/0.3.21/futures/future/struct.OptionFuture.html). + +Using match, you can avoid that by supporting `.await` directly. + +```rust +context.client + .post("https://example.com/crabs") + .body("favourite crab?") + .send() + .await + .match { + Err(_) => Ok("Ferris"), + Ok(resp) => resp.json::>().await, + // this works in a postfix-match ^^^^^^ + } +``` + # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -This is the technical portion of the RFC. Explain the design in sufficient detail that: +`X.Y.match {}.Z` + +Will be interpreted as -- Its interaction with other features is clear. -- It is reasonably clear how the feature would be implemented. -- Corner cases are dissected by example. +```rust +match X.Y {}.Z` +``` -The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. +I believe this would be the same precedence as `await`. # Drawbacks [drawbacks]: #drawbacks @@ -229,19 +272,14 @@ still not close to agreeing on syntax or behaviour. # Prior art [prior-art]: #prior-art -Discuss prior art, both the good and the bad, in relation to this proposal. -A few examples of what this can include are: +## `await` -- For language, library, cargo, tools, and compiler proposals: Does this feature exist in other programming languages and what experience have their community had? -- For community proposals: Is this done by some other community and what were their experiences with it? -- For other teams: What lessons can we learn from what other communities have done here? -- Papers: Are there any published papers or great posts that discuss this? If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. +`await` was initially proposed to be a prefix keyword. -This section is intended to encourage you as an author to think about the lessons from other languages, provide readers of your RFC with a fuller picture. -If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or if it is an adaptation from other languages. +There was a [suggestion to make it postfix](https://github.com/rust-lang/rfcs/pull/2394#discussion_r179929778) for very similar reasons (not breaking up method chains). -Note that while precedent set by other languages is some motivation, it does not on its own motivate an RFC. -Please also take into consideration that rust sometimes intentionally diverges from common language features. +This eventually became the favourite given the pain that await chains introduces in other languages. +I've heard many accounts from people that postfix-await is one of their favourite features of the language. # Unresolved questions [unresolved-questions]: #unresolved-questions @@ -255,20 +293,4 @@ usecases of match would cause more [subtle bugs](https://fasterthanli.me/article # Future possibilities [future-possibilities]: #future-possibilities -Think about what the natural extension and evolution of your proposal would -be and how it would affect the language and project as a whole in a holistic -way. Try to use this section as a tool to more fully consider all possible -interactions with the project and language in your proposal. -Also consider how this all fits into the roadmap for the project -and of the relevant sub-team. - -This is also a good place to "dump ideas", if they are out of scope for the -RFC you are writing but otherwise related. - -If you have tried and cannot think of any future possibilities, -you may simply state that you cannot think of anything. - -Note that having something written down in the future-possibilities section -is not a reason to accept the current or a future RFC; such notes should be -in the section on motivation or rationale in this or subsequent RFCs. -The section merely provides additional information. +Eventually more operators could become postfix, such as `for_each` From 1c777693d1f438efdc4b1ed32e6a03503eba3393 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sat, 23 Jul 2022 09:07:04 +0100 Subject: [PATCH 4/7] alternatives --- text/0000-postfix-match.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/text/0000-postfix-match.md b/text/0000-postfix-match.md index bb031760bf5..e07ed860d3e 100644 --- a/text/0000-postfix-match.md +++ b/text/0000-postfix-match.md @@ -143,6 +143,7 @@ While I am not at liberty to share the codebase, the former is equivalent to som I see on some of our codebases at work. ## tap (pipelines) +[guide-level-explanation]: #tap-pipelines While not the intended use of this proposal, [tap](https://crates.io/crates/tap) is a popular crate to allow more advanced pipeline operations. @@ -251,6 +252,8 @@ make the language more flexible such that match statements aren't a hindrance. ## Alternatives +### Postfix Macros + [postfix macros](https://github.com/rust-lang/rfcs/pull/2442) have been an idea for many years now. If they were to land, this feature could easily be implemented as a macro (bikeshedding on postfix macro syntax): @@ -269,6 +272,19 @@ macro match_! ( However, after years of discussion and hundreds of thumbs-ups, it feels like we're still not close to agreeing on syntax or behaviour. +### Pipes + +I've already mentioned [tap](#tap-pipelines) for how we can do prefix-in-postfix, +so we could promote the use of `.pipe` instead. However, using the pipe method makes +async awkward and control flow impossible. + +Alternatively we could have a new builtin pipeline operator +(e.g. `|>`[0] or `.let x {}`>[1]) +but this is brand new syntax and requires a whole new set of discussions. + +[0]: https://internals.rust-lang.org/t/idea-operator-for-postfix-calls-to-macros-and-free-functions/7634 +[1]: https://internals.rust-lang.org/t/idea-postfix-let-as-basis-for-postfix-macros/12438 + # Prior art [prior-art]: #prior-art @@ -293,4 +309,4 @@ usecases of match would cause more [subtle bugs](https://fasterthanli.me/article # Future possibilities [future-possibilities]: #future-possibilities -Eventually more operators could become postfix, such as `for_each` +I can't think of anything related to match that could be improved in this area From ce401021062d35776ea64e64d85bd94d1b9e1cec Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Sat, 23 Jul 2022 09:23:58 +0100 Subject: [PATCH 5/7] typos --- text/0000-postfix-match.md | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/text/0000-postfix-match.md b/text/0000-postfix-match.md index e07ed860d3e..ccf50c95b67 100644 --- a/text/0000-postfix-match.md +++ b/text/0000-postfix-match.md @@ -6,7 +6,7 @@ # Summary [summary]: #summary -An alternative postfix syntax for match expressions that allows for interspercing match statements with function chains +An alternative postfix syntax for match expressions that allows for interspersing match statements with function chains ```rust foo.bar().baz.match { @@ -31,11 +31,11 @@ of the code. Sometimes, these method chains can become quite terse for the sake of composability -Forever we hear the complaints of fresh rustaceans learning about option/result -method chaining being [very surprised by the ordering](https://github.com/rust-lang/rfcs/issues/1025) of the methods like +For instance, we have the [surprising ordering](https://github.com/rust-lang/rfcs/issues/1025) +of the methods like [`map_or_else`](https://doc.rust-lang.org/std/result/enum.Result.html#method.map_or_else). -This RFC proposes promoting the use of match statements by supporting postfix-match, reducing the use of some of these methods terse and potentially confusing method chains. +This RFC proposes promoting the use of match statements by supporting postfix-match, reducing the use of some of these terse methods and potentially confusing method chains. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -46,9 +46,9 @@ variant. Some powerful techniques like pattern binding, nested patterns and or p allow for some versatile and concise, but still fairly readable syntax for dealing with these types. -Rust often features functional approachs to lots of problems. For instance, +Rust often features functional approaches to lots of problems. For instance, it's very common to have chains of `map`, `and_then`, `ok_or`, `unwrap` -to process some `Option` or `Result` type in a pipeline, rather than continously reassigning to new variable bindings. +to process some `Option` or `Result` type in a pipeline, rather than continuously reassigning to new variable bindings. ```rust let x = Some(42); @@ -59,7 +59,7 @@ let magic_number = x.map(|x| x * 5) ``` Some of these provided method chains are fairly readable, like the ones presented above, -but sometimes the desire to use long method chains is met with unweildy hacks or awkward function arguments. +but sometimes the desire to use long method chains is met with unwieldy hacks or awkward function arguments. ```rust let x = Some("crustaceans"); @@ -201,7 +201,7 @@ context.client .await .match { Err(_) => Ok("Ferris"), - Ok(resp) => resp.json::>().await, + Ok(resp) => resp.json::().await, // this works in a postfix-match ^^^^^^ } ``` @@ -254,12 +254,12 @@ make the language more flexible such that match statements aren't a hindrance. ### Postfix Macros -[postfix macros](https://github.com/rust-lang/rfcs/pull/2442) have been an idea for many years now. If they were to land, this feature -could easily be implemented as a macro (bikeshedding on postfix macro syntax): +[postfix macros](https://github.com/rust-lang/rfcs/pull/2442) have been an idea for many years now. +If they were to land, this feature could easily be implemented as a macro: ```rust macro match_! ( - postfix { $( + { $self:expr; $( $arm:pat => $body:expr, )+ } => { match $self { $( @@ -275,10 +275,19 @@ still not close to agreeing on syntax or behaviour. ### Pipes I've already mentioned [tap](#tap-pipelines) for how we can do prefix-in-postfix, -so we could promote the use of `.pipe` instead. However, using the pipe method makes +so we could promote the use of `.pipe()` instead. However, using the pipe method makes async awkward and control flow impossible. -Alternatively we could have a new builtin pipeline operator +```rust +x.pipe(|x| async { + match x { + Err(_) => Ok("Ferris"), + Ok(resp) => resp.json::().await, + } +}).await +``` + +We could add a new builtin pipeline operator (e.g. `|>`[0] or `.let x {}`>[1]) but this is brand new syntax and requires a whole new set of discussions. @@ -304,7 +313,7 @@ I've heard many accounts from people that postfix-await is one of their favourit Method call chains will not lifetime extend their arguments. Match statements, however, are notorious for having lifetime extension. It is currently unclear if promoting these -usecases of match would cause more [subtle bugs](https://fasterthanli.me/articles/a-rust-match-made-in-hell#my-actual-bug), or if it's negligable +use-cases of match would cause more [subtle bugs](https://fasterthanli.me/articles/a-rust-match-made-in-hell#my-actual-bug), or if it's negligible # Future possibilities [future-possibilities]: #future-possibilities From fb8769b9994a0c5601d0d7913a51790f0d7800b5 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Wed, 31 Aug 2022 13:34:28 +0100 Subject: [PATCH 6/7] demote tap proposal and explain precedence --- text/0000-postfix-match.md | 70 +++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/text/0000-postfix-match.md b/text/0000-postfix-match.md index ccf50c95b67..31180458fea 100644 --- a/text/0000-postfix-match.md +++ b/text/0000-postfix-match.md @@ -145,47 +145,13 @@ I see on some of our codebases at work. ## tap (pipelines) [guide-level-explanation]: #tap-pipelines -While not the intended use of this proposal, [tap](https://crates.io/crates/tap) is a popular crate to allow more advanced pipeline operations. +While postfix match with a single match arm can replicate a pipeline operator, +this should be actively condemned for a more well defined syntax or method actually intended for this purpose. -```rust -let val = original_value - .pipe(first) - .pipe(|v| second(v, another_arg)) - .pipe(third) - .pipe(|v| last(v, another_arg)); -``` - -This can be written similarly using our postfix match: - -```rust -let val = original_value - .match { v => first(v) } - .match { v => second(v, another_arg) } - .match { v => third(v) } - .match { v => last(v, another_arg) }; -``` +We already have a clippy lint [`clippy::match_single_binding`](https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding) that covers this case This avoids the need for a new dedicated pipeline operator or syntax. -### into - -Occasionally I've bumped into the difficulty of using `Into` in a postfix setting. -The tap crate also provides a `Conv` trait to convert in a method chain using turbofish. - -```rust -let upper = "hello, world" - .conv::() - .tap_mut(|s| s.make_ascii_uppercase()); -``` - -This can also be emulated with postfix-match - -```rust -let upper = "hello, world" - .match { s => String::from(s) } - .match { mut s => { s.make_ascii_uppercase(); s } } -``` - ## async support One thing of note is that in option chains you cannot use futures unless you use adapters @@ -202,7 +168,7 @@ context.client .match { Err(_) => Ok("Ferris"), Ok(resp) => resp.json::().await, - // this works in a postfix-match ^^^^^^ + // this works in a postfix-match ^^^^^^ } ``` @@ -217,7 +183,7 @@ Will be interpreted as match X.Y {}.Z` ``` -I believe this would be the same precedence as `await`. +And this will be the same precedence as `await` for consistency with all `.` based prefix operators and methods we have. # Drawbacks [drawbacks]: #drawbacks @@ -252,6 +218,32 @@ make the language more flexible such that match statements aren't a hindrance. ## Alternatives +### Precedence + +`*` and `&` are very unfortunately low priority prefix operators in our syntax grammar. +If `.match` has a higher prefix, this can be a little confusing as shown below + +```rust +*foo.match { + Ok(3) => …, + Ok(100) => …, + _ => …, +} +``` + +where this is parsed as + +```rust +*(match foo { + Ok(3) => …, + Ok(100) => …, + _ => …, +}) +``` + +C# has a [postfix switch expression](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/#operator-precedence) where `switch` +has a lower precedence than methods and deref. This is something we could explore, not if we use `.match` as the syntax. + ### Postfix Macros [postfix macros](https://github.com/rust-lang/rfcs/pull/2442) have been an idea for many years now. From 6b7cecfbaa4f11d0beb4839a113d63e71c98aa38 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Thu, 19 Jan 2023 11:09:52 +0000 Subject: [PATCH 7/7] add comment on future postfix syntax Co-authored-by: Josh Triplett --- text/0000-postfix-match.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-postfix-match.md b/text/0000-postfix-match.md index 31180458fea..af63d7377fd 100644 --- a/text/0000-postfix-match.md +++ b/text/0000-postfix-match.md @@ -310,4 +310,4 @@ use-cases of match would cause more [subtle bugs](https://fasterthanli.me/articl # Future possibilities [future-possibilities]: #future-possibilities -I can't think of anything related to match that could be improved in this area +In theory, some other Rust constructs could also have postfix alternatives, but this RFC should not be taken as precedent for doing so. This RFC only proposes postfix `match`.