Skip to content

Add support for pattern additions #1026

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

Draft
wants to merge 3 commits into
base: draft-v9
Choose a base branch
from

Conversation

RexJaeschke
Copy link
Contributor

This PR might be incomplete; read below.

Regarding the MS proposal:

  1. Type patterns: Grammar rule primary_pattern is defined as something different from pattern, but as best as I can tell, they are exactly the same thing, so I replaced all occurrences of primary_pattern with pattern. Is that OK? (Also, the use of primary suggests here are secondary/other forms, but I don't see what they are.)
  2. Relational patterns: the proposed grammar shows relational_expression as the operand of each relational pattern, but the accompanying narrative goes on to constrain such relational expressions to constants only. So what not use *constant_expression" instead? And that's what I did. Am I missing something?
  3. Relational patterns: The proposal did not include support for enums, but as they are supported, I included them in the spec.
  4. Logical patterns: The proposal calls these pattern combinators; however, that term is not used elsewhere on MS's tutorial pages, so I used the more obvious (and elsewhere used) logical patterns instead.
  5. Logical patterns: The fact that the rule logical_pattern always expands to disjunctive_pattern may seem unnecessary, but it allows the placement of logical_pattern in the rule pattern rather than pushing the (odd-looking) disjunctive_pattern up there instead. (We use this approach elsewhere in the grammar.)
  6. The (substantial) second half of the proposal, "Open Issues with Proposed Changes," raises questions/issues. However, unlike all (or at least most) other MS proposals I've worked with, there is no follow-on discussion to say how these topics were actually addressed in the final implementation. Certainly, if any of the suggested approaches were taken, more words will need to be added to this PR to reflect that. I'll need help from someone at MS to resolve this.

This PR was created based on the assumption that the edits proposed by PR #873 for V8-related pattern-matching features will be adopted, and no other non-trivial edits will be made to that part of V8. When that PR is finally merged, this PR might need adjustment to reflect any changes in the V8 proposal review/adoption.

@RexJaeschke RexJaeschke added the type: feature This issue describes a new feature label Dec 7, 2023
@RexJaeschke RexJaeschke added this to the C# 9.0 milestone Dec 7, 2023
@RexJaeschke RexJaeschke marked this pull request as draft December 7, 2023 13:08
@gafter gafter self-assigned this Jan 16, 2024
@gafter
Copy link
Member

gafter commented Dec 11, 2024

Regarding the OP, I have the following comments:

(1) Re "Type patterns: Grammar rule primary_pattern is defined as something different from pattern, but as best as I can tell, they are exactly the same thing, so I replaced all occurrences of primary_pattern with pattern. Is that OK? (Also, the use of primary suggests here are secondary/other forms, but I don't see what they are.)"

Several kinds of patterns are not primary_patterns. Specifically: disjunctive_pattern, conjunctive_pattern, and negated_pattern.

(2) Re: "Relational patterns: the proposed grammar shows relational_expression as the operand of each relational pattern, but the accompanying narrative goes on to constrain such relational expressions to constants only. So what not use *constant_expression" instead? And that's what I did. Am I missing something?"

Yes, there is a reason. The grammar rule for constant_expression makes it equivalent to expression (see section 12.23). So it includes, for example, operators at a looser precedence level, such as equality_expression which in this context it ought not do. Your change makes the following code ambiguous:

x = a is < b == c;

Because the left operand of the == c could be a is < b (correct) or it could be b (incorrect) due to your change.

(3) Re: "Relational patterns: The proposal did not include support for enums, but as they are supported, I included them in the spec."

Yes, good.

(4) Re: "Logical patterns: The proposal calls these pattern combinators; however, that term is not used elsewhere on MS's tutorial pages, so I used the more obvious (and elsewhere used) logical patterns instead."

Yes, good.

(5) Re: "Logical patterns: The fact that the rule logical_pattern always expands to disjunctive_pattern may seem unnecessary, but it allows the placement of logical_pattern in the rule pattern rather than pushing the (odd-looking) disjunctive_pattern up there instead. (We use this approach elsewhere in the grammar.)"

Okay, but I don't see a problem with using disjunctive_pattern as a right-hand-side in the rule for pattern.

(6) Re: "The (substantial) second half of the proposal, "Open Issues with Proposed Changes," raises questions/issues. However, unlike all (or at least most) other MS proposals I've worked with, there is no follow-on discussion to say how these topics were actually addressed in the final implementation. Certainly, if any of the suggested approaches were taken, more words will need to be added to this PR to reflect that. I'll need help from someone at MS to resolve this."

We should open issues for each of the open issues (or one issue for all of them) to make sure we address them.

@@ -2,7 +2,7 @@

## 11.1 General

A ***pattern*** is a syntactic form that can be used with the `is` operator ([§12.12.12](expressions.md#121212-the-is-operator)) and in a *switch_statement* ([§13.8.3](statements.md#1383-the-switch-statement)) to express the shape of data against which incoming data is to be compared. A pattern is tested against the *expression* of a switch statement, or against a *relational_expression* that is on the left-hand side of an `is` operator, each of which is referred to as a ***pattern input value***.
A ***pattern*** is a syntactic form that can be used with the `is` operator ([§12.12.12](expressions.md#121212-the-is-operator)) and in a *switch_statement* ([§13.8.3](statements.md#1383-the-switch-statement)) to express the shape of data against which incoming data is to be compared. A pattern is tested against the *expression* of a switch statement, or against a *relational_expression* that is on the left-hand side of an `is` operator, each of which is referred to as a ***pattern input value***. Patterns may be combined using Boolean logic.
Copy link
Member

Choose a reason for hiding this comment

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

I don't know what "Patterns may be combined using Boolean logic" means. Yes, there are pattern forms for disjunction, conjunction, and negation, but the "Boolean logic" sentence suggests something more general.


Relational patterns support the relational operators `<`, `<=`, `>`, and `>=` on all of the built-in types that support such binary relational operators with both operands having the same type: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `nint`, `nuint`, and enums.

It is a compile-time error if `constant_expression`is `double.NaN`, `float.NaN`, or `null_literal`.
Copy link
Member

Choose a reason for hiding this comment

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

Not exactly. It is not a syntactic constraint. It is a compile-time error if it evaluates to one of those values.


§logical-pattern-new-clause Logical pattern

A *logical_pattern* is used to negate a pattern input value ([§11.1](patterns.md#111-general)) or to combine that value with a pattern using a Boolean operator.
Copy link
Member

Choose a reason for hiding this comment

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

No, it doesn't negate the input value. It inverts (in the boolean sense) the result of the pattern-match. Similarly, the combination doesn't happen with the value, but with the result of pattern-match tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

If is an operation of many names: not, invert & negate, and in C# it is indeed called logical negation (§12.9.4).

Copy link
Member

Choose a reason for hiding this comment

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

I'm not concerned with which of those names we use. I'm pointing out that the meaning is not "to negate a pattern input value", but rather to negate the result of determining whether or not the input value matches the pattern.


> *Note*: As indicated by the grammar, `not` has precedence over `and`, which has precedence over `or`. This can be explicitly indicated or overridden by using parentheses. *end note*

When a *pattern* is used with `is`, any pattern operators in that *pattern* have higher precedence than their logical operator counterparts. Otherwise, those pattern operators have lower precedence.
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what this means. An example would be helpful.

@@ -12,9 +12,13 @@ A pattern may have one of the following forms:

```ANTLR
pattern
: declaration_pattern
: '(' pattern ')'
Copy link
Member

Choose a reason for hiding this comment

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

It is worth a sentence to say what this means.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: feature This issue describes a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants