Open gafter opened 7 years ago
Rather than implementing this limited feature, could the team just finish implementing pattern matching, including match
expressions and get that released, please?
@DavidArno Haha there is a thing called "priorities".
@bondsbw,
Exactly. They should prioritise finishing the half-complete pattern matching feature over adding new features like nullable reference types and those interface thingies 😉
@DavidArno I agree that match
expression would be awesome to have sooner than later but don't know if this is the place to discuss priorities, it's a reasonable suggestion, at least in my opinion.
p.s. I wouldn't downvote something just due to priorities, not saying you did but just a side note. 😉
I feel like these partial infix expressions could be a more general feature.
iqs.Where(x => x < 100)
could be simplified to
iqs.Where(< 100)
@bondsbw Well, if you think that this feature should be generalized then I think that it warrants a new post.
I'll start a new post if there is interest.
The pattern match already can handle this for now:
var a = 16;
switch (a)
{
case int _ when a < 100:
Console.WriteLine(a);
break;
case int _ when a < 200:
Console.WriteLine(a + a);
break;
}
With when
you can do a more complex play:
var a = 16;
switch (a)
{
case int _ when a < 100:
Console.WriteLine(a);
break;
case int _ when IsOK(a):
Console.WriteLine(a + a);
break;
}
private bool IsOK(int a) => true; //<- replace with your own logic
The weak point is, you can not pass a long
to the switch, and the when clause is indeed a bit long.
Very good proposal
I'm championing this as the idea of having comparison-based pattern-matching forms.
@gafter
Neat. Ideas around syntax?
if (person is Student { Gpa: > 3.0 }) { ... }
@HaloFour Yes, that syntax is fine. Also case > 10
. Not sure how it should work when the input is of type object, for example.
I'm curious if that syntax can be generalized into partial application.
@bondsbw Can you give an example? Remember these are patterns, not expressions.
For ranges, I expect the syntax would be something like in 1 to 10
, for example
case in 1 to 10:
if (x is in 1 to 10)
etc.
@gafter This would be outside of pattern matching, outside of the scope of the current proposal but related.
The idea would be to open up expressions like I mentioned above:
iqs.Where(< 100)
Say we have a binary operator x op y
with the function signature Tx * Ty -> Tresult
. Then x op
would be a partial application with function signature Ty -> Tresult
, and op y
would be a partial application with function signature Tx -> Tresult
.
To tie it all together, partial applications could be substituted for method groups with a compatible signature. < 100
has the signature int -> bool
and is compatible with the predicate
parameter of Where
.
A different idea... allow patterns to be substituted for any method group with signature T -> bool
.
Then we could have
iqs.Where(is < 100)
but also the much broader range of patterns:
iqs.Where(is in 120 to 140)
people.Where(is Student { Gpa: > 3.0 })
@bondsbw How would your first idea work with operators that are both binary and unary, like +
, -
or *
?
In other words, iqs.Select(- 100)
is already valid syntax (which may or may not actually compile, depending on overload resolution), so I don't think you could change its meaning.
@svick +
and -
are the only ones that could be ambiguous (I think... please correct me). In those cases it would have to prefer to interpret it as the unary operator, for the sake of BC.
I think I prefer the pattern approach, though it is limited to situations where the return value is bool
.
Any operator with both a binary and unary form could trigger this ambiguity - which includes *
, &
and |
as well.
Building on the pattern matching syntax we already have, the when syntax opens up every possible predicate in an extremely readable manner.
Id like to propose an extension to this.
Where you can do something like this:
int a = 3;
int b = 2;
int c = 1;
switch (a) {
case ((& c) == c):
Console.WriteLine("(a & c) == c");
break;
case (>> 1 == c):
Console.WriteLine("(a >> 1) == c");
break;
case (-b == c):
Console.WriteLine("(a - b) == c");
break;
}
Might be silly though. (Sorry, not sure on how to format code in a comment)
@Mattias-Viklund your last switch case is a bit flawed, as it would be confusing whether you meant a-b == c
or -b == c
(both are currently valid expressions).
I would rather see a Haskell-like currying and partial application of operators, however, this would require currying in general to be introduced to C#. This would allow expressions such as:
Func<int, int> = (>>2);
...which could be applied to your example above in a more general manner.
Oh yeah of course, dumb oversight on my part. but yeah I would want something to add to switches in order to make them more flexible.
Would this also work with strings, as in VB.NET?
var s = GetArbitraryString();
switch (s)
case >= "n":
Console.WriteLine("Past the midpoint");
break;
case "m" to "n":
Console.WriteLine("Starts with 'm');
break;
}
@zspitz : Strings would have to define comparison operators like they do in VB.NET. So, as long as they are not defined, your code wouldn't work.
However, you could currently "solve" your code sample by replacing strings with chars:
string s = ........;
switch (s[0])
{
case >= 'n':
Console.WriteLine("Past the midpoint");
break;
case 'm' to 'n':
Console.WriteLine("Starts with 'm'");
break;
}
I would like to vote against the to
syntax. It still very ambiguous
And I would favor and
and or
syntax in pattern instead
So 1 to 10
would just become >= 1 and <= 10
or > 0 and < 11
The LDM confirmed this as part of a set of pattern-matching features for consideration in C# 9.0. This depends for its utility on the and
pattern combinator, so we would not do it before that.
@JFMous commented on Sat May 14 2016
It would be nice if the case labels in switch statement supported comparison operators, much like the Select Case statement in Visual Basic does.
Now, there are only two options for the switch labels:
This could be extended to:
So you could write code as in this example:
The 'to' keyword would be used to specify a range. In the statement
switch (value)
,case x to y:
would be equivalent to the boolean expressionvalue >= x && value <= y
@HaloFour commented on Sat May 14 2016
Case guards in pattern matching #206 will open this up to allowing for arbitrary conditions:
The wildcard pattern would match on anything but then the case guard would contain the specific conditions. They would be evaluated in lexical order.
@alrz commented on Sun May 15 2016
would it make sense to make
case
optional or perhaps switch expression?might be preferrable over if else.
@bondsbw commented on Mon May 16 2016
@alrz I like that somewhat, feels like a reasonable simplification.
But I feel this may be even more useful in pattern matching. In match expressions, the roughly equivalent form might be:
I like the possibilities but if
iq
is always the comparison, it really feels like it should be the subject of the match expression. Something like the following feels more like pattern matching (although it would require a bit of rethinking what a relational expression is):And I'm not sure I like changing
into something like
@Unknown6656 commented on Mon May 23 2016
@bondsbw, @JFMous : I would like to see something like the following implemented with the
match
-pattern:Meaning, the possibility to use the match-statement inside of expressions.
@HaloFour commented on Mon May 23 2016
@Unknown6656 The proposal is that
match
is an expression, so of course you'd be able to use it within other expressions. You can think of it like a ternary op on steroids.As for your specific example, there have been no proposed range patterns. Nor has there been a proposal to allow for only case guards with an implied wildcard pattern. So as of now your example would be: