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

Champion "and, or, and not patterns" (VS 16.8, .NET 5) #1350

Open
5 tasks
gafter opened this issue Mar 1, 2018 · 129 comments
Open
5 tasks

Champion "and, or, and not patterns" (VS 16.8, .NET 5) #1350

gafter opened this issue Mar 1, 2018 · 129 comments
Assignees
Labels
Design Review Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Milestone

Comments

@gafter
Copy link
Member

gafter commented Mar 1, 2018

  • Proposal added
  • Discussed in LDM
  • Decision in LDM
  • Finalized (done, rejected, inactive)
  • Spec'ed

The idea is to add three new pattern forms

  1. pattern and pattern
  2. pattern or pattern
  3. not pattern

The latter two would not be permitted to define pattern variables in the subpatterns (as they would never be definitely assigned).

We'd have to decide on syntax and precedence, and whether some mechanism such as parentheses could be used for grouping patterns to override precedence.

Examples:

switch (o)
{
    case 1 or 2:
    case Point(0, 0) or null:
    case Point(var x, var y) and var p:
}
@alrz
Copy link
Contributor

alrz commented Mar 1, 2018

The latter two would not be permitted to define pattern variables in the subpatterns

For or patterns, as mentioned in #118 we can allow "identical types" for overlapping pattern variables,

switch (o)
{
    // x must be of the same type in both patterns

    case Point(0, var x):
    case Point(var x, 0):
        break;

    case Point(0, var x) or Point(var x, 0):
        break;
}

Alternatively we could use the "most specific common type" for overlapping variables,

switch (o) {
  case A x:
  case B x:
    CommonBase c = x;
    break;
}

but just identical-types would be still useful most of the time as demonstrated by F#.

@HaloFour
Copy link
Contributor

HaloFour commented Mar 1, 2018

I'm with @alrz, I think that allowing the operands of the or patterns to introduce pattern variables would be a powerful feature with the requirement that the pattern variables must have the same type and must be assigned by both sides.

@bondsbw
Copy link

bondsbw commented Mar 1, 2018

An alternative to "most specific common type" is the intersection type A | B.

@MgSam
Copy link

MgSam commented Mar 2, 2018

I vote for using &&, ||, ! and not introducing yet more operators that do almost the exact same thing.

@HaloFour
Copy link
Contributor

HaloFour commented Mar 2, 2018

@MgSam

IIRC that would introduce ambiguities when patterns are used as Boolean expressions.

dotnet/roslyn#6235

@ufcpp
Copy link

ufcpp commented Mar 2, 2018

Are intersection and union types too difficult to implement?

@yaakov-h
Copy link
Member

yaakov-h commented Mar 2, 2018

Since the first two join two separate patterns, am I correct in understanding that the following would be valid?:

if (o is IDictionary d and IEnumerable e) {
    // object.ReferenceEquals(d, e) == true
    // (assuming no boxing)
}
if (o is IDictionary and IEnumerable e) {
    // e is IEnumerable only, there is no IDictionary variable created
}

@gafter
Copy link
Member Author

gafter commented Mar 2, 2018

@ufcpp How would intersection and union types help with case 1 or 2:?

@gafter
Copy link
Member Author

gafter commented Mar 2, 2018

@yaakov-h Regarding your first example, yes. The second example doesn't make sense as IDictionary is not a pattern.

@Unknown6656
Copy link
Contributor

Unknown6656 commented Mar 2, 2018

Also consider implementing xor patterns (or ^ if one does not like the word xor).
It would of course -as with or- not be permitted to define pattern variables.

@jnm2
Copy link
Contributor

jnm2 commented Mar 2, 2018

Also consider implementing xor patterns

Why?

@MgSam
Copy link

MgSam commented Mar 2, 2018

@HaloFour What's better? A feature that's ambiguous for the developer or one that's ambiguous for the compiler?

If they can't implement with the existing operators, it's not worth doing. This will just cause endless confusion if added like this. You'll get people trying to write:

if(condition and condition || condition)

More generally, C# team, please stop adding brand new keywords for minor use cases. The in disaster should be enough of a lesson for the reason why.

@gafter
Copy link
Member Author

gafter commented Mar 2, 2018

@MgSam What's worse is one that is ambiguous for both the developer and the compiler.

@bondsbw
Copy link

bondsbw commented Mar 2, 2018

@MgSam I wouldn't call patterns a "minor use case".

if(condition and condition || condition)

This is not a pattern, or anything else that is or would be accepted by the compiler.

@gafter
Copy link
Member Author

gafter commented Mar 3, 2018

@MgSam You suggestion gives two different contradictory interpretations for this code, one of which is accepted today.

if (myBool is true || false)

@Unknown6656
Copy link
Contributor

Unknown6656 commented Mar 3, 2018

@jnm2

Why?

First to be consistent with or and and.
Second: You often will find a case where you are semantically asking, whether an object X is either A or B, e.g. when checking for numeric non-continuous ranges, discriminated unions. ...

Forget it - xor is a bad idea.

@Richiban
Copy link

Richiban commented Mar 7, 2018

With and-patterns and or-patterns we will finally have a way of comparing a variable against a given list of multiple values, just as every newbie programmer wants to do in any language 😁

if(x is 1 or 2 or 3)
{
    // Hooray!
}

@alrz
Copy link
Contributor

alrz commented Mar 7, 2018

what if we add this in the LHS of the is operator 🤔

if (x and y is not null)

@GeraudFabien
Copy link

GeraudFabien commented Mar 7, 2018

@Richiban newbie may do with a IEnumerable (Here i use an array).
(new []{1,2,3}).Contains(x)

@bondsbw
Copy link

bondsbw commented Mar 7, 2018

@alrz

if (x and y are not null)

FTFY. 😉

@jnm2
Copy link
Contributor

jnm2 commented Mar 7, 2018

if (neither x nor y are null)

😁

@Thaina
Copy link

Thaina commented Mar 8, 2018

This is too funny please staph

@Unknown6656
Copy link
Contributor

Unknown6656 commented Mar 8, 2018

@JMN2: Looks suspiciously like VB.NET...... (.__.)

If Neither x Nor y Are Nothing Then
    ' Just kiddin' - although it would funny to see,
    ' whether the VB compiler accepts Shakespeare's works as valid code
End If

@MadsTorgersen MadsTorgersen added this to the 8.X candidate milestone Mar 19, 2018
@dotnet dotnet deleted a comment Apr 19, 2018
@dotnet dotnet deleted a comment from HaloFour Apr 19, 2018
@spydacarnage
Copy link

spydacarnage commented Jul 12, 2020 via email

@luo4neck
Copy link

I think this is a good pattern

var a = x switch
{
    | 3 || 4 => "hey"
    | _ => "yoo"
}

@HaloFour
Copy link
Contributor

@luo4neck

C# already has a switch expression syntax which does not use |, and patterns can be used outside of switch expressions where it has been discussed that || would be ambiguous.

@Unknown6656
Copy link
Contributor

Unknown6656 commented Jul 12, 2020

I think this is a good pattern

What about the following?

bool? c = ...;

var x = c switch {
    | true || false => "the value 'c' is 'true' or 'false' ... or is it?"
    | _ => "'c' is something else."
};

Would true || false be reduced to true or would it mean true or false?
You can play around with that example yourself.

@luo4neck
Copy link

@HaloFour @Unknown6656
Actually I think combination of pattern matching and DU in F# is pretty good
Maybe have pattern matching without switch could be a plan

At least for myself, pattern matching together with DU is more important than beautiful/ugly grammer

@af4jm
Copy link

af4jm commented Jul 17, 2020

So having read through all the comments above, it seems the idea is to introduce new keywords so operator precedence can be different than it is with the && || operators? If you're going to add an "or" operator, it should have the exact same precedence as || and |, similar for "and" && & operators... If the precedence is different, that's a bad idea because it's the most confusing for humans... and if they're kept the same to keep the humans sane, then there's no point in adding a different operator...

Semantically I don't see how "and" v. && makes a bit of difference (as opposed to & which does does its and'ing differently)

@u7pro
Copy link

u7pro commented Jul 17, 2020

So having read through all the comments above, it seems the idea is to introduce new keywords so operator precedence can be different than it is with the && || operators? If you're going to add an "or" operator, it should have the exact same precedence as || and |, similar for "and" && & operators... If the precedence is different, that's a bad idea because it's the most confusing for humans... and if they're kept the same to keep the humans sane, then there's no point in adding a different operator...

Semantically I don't see how "and" v. && makes a bit of difference (as opposed to & which does does its and'ing differently)

@af4jm : It's not about operators precedence..

pattern1 or pattern2 will mean that any of those patterns is considered as a valid case, not the logical operation result of both them..

Example, if you say case true or false, it will mean both values true and false are valid cases..

whereas if you say case true || false, this will mean only true value is valid because || operation will be evaluated..

@af4jm
Copy link

af4jm commented Jul 17, 2020

@u7pro that's kind of my point, this proposal would make the statement read or pronounced as "true or false" means 2 very different things depending whether or is spelled "or" or "||" (as opposed to "|" which is pronounved "bitwise or") there's got to be something better than reusing VB.NET's verbose version of "||" to mean something that VB's Or doesn't mean (not that I plan to either read or write VB again in my career, but the comparison is another example of the confusuion

@333fred
Copy link
Member

333fred commented Jul 17, 2020

The problem is that if (a is true || false) already has meaning today. We can't change it.

@af4jm
Copy link

af4jm commented Jul 20, 2020

OK, so I see the point, but it still smells bad, really bad (the proposed syntax, NOT the functionality behind it)... the "or" and "not" cases are syntactic sugar and trivial to achieve the same functionality today, but not so for the "and", and if you're doing "and" it makes sense to do "or" also because it does reduce code duplication... I know the follow-up to "it smells bad" is "suggestion that doesn't", but I don't have one (well, I could think of a few, but they also smell bad... worse actually), which I guess means I should withdraw my objection

@jcouv jcouv changed the title Champion "and, or, and not patterns" Champion "and, or, and not patterns" (VS 16.8, .NET 5) Sep 1, 2020
@MadsTorgersen MadsTorgersen modified the milestones: 9.0 candidate, 9.0 Sep 9, 2020
@333fred 333fred added the Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification label Oct 16, 2020
@ByteEater-pl
Copy link

I used some sophisticated language in #1350 (comment), that may be why it seems to have gone ignored, so let me summarize in simple terms: if variables under arbitrarily nested and and or are considered to be definitely assigned (perhaps with some restrictions on types in the case of or), then just as well can be those having an even number of nots above.

@ericsampson
Copy link

Didn't this topic basically get implemented in C#9 ?

@orthoxerox
Copy link

@ericsampson It did, but the issue will only be closed when the spec is updated, hence the new label.

@ericsampson
Copy link

Thanks @orthoxerox, I thought so and saw the label which made sense, I just thought it was odd that people were still commenting with ideas/proposals - those will have to wait for vNext! :)

@ByteEater-pl
Copy link

@ericsampson will additional features require a new issue? If so, I hope the relevant parts from this one will be included or at least mentioned and referenced there.

@ericsampson
Copy link

@ByteEater-pl I'm not on the .NET team, but I personally wouldn't rely on that. If there's anything else that you'd like to see implemented, I think it would most likely to be noticed in a new discussion. But again I could be wrong, I'm not on the team :)

@333fred
Copy link
Member

333fred commented Nov 9, 2020

@ericsampson will additional features require a new issue? If so, I hope the relevant parts from this one will be included or at least mentioned and referenced there.

Yes, new feature requests will need new discussions/issues.

@ismailaidar
Copy link

We would like more built in functions instead.

@ismailaidar
Copy link

what about this? int x = 10 if (condition) ;

@HaloFour
Copy link
Contributor

@ismailaidar

I'd suggest opening new discussions if you want to propose features that aren't related to the current discussion.

@viclang
Copy link

viclang commented Oct 4, 2021

This should 'not' be possible if(key is not not not null)

@jnm2
Copy link
Contributor

jnm2 commented Oct 4, 2021

Why is that worse than the language allowing if (!!!condition)? You can do this with anything.

@viclang
Copy link

viclang commented Oct 4, 2021

Why is that worse than the language allowing if (!!!condition)? You can do this with anything.

I didn't expect it was possible before but yes, depending on the condition it still means true or false, A true point. It was funny to see it in plain english and it all still compiles like nothing happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Review Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Projects
None yet
Development

No branches or pull requests