Replies: 9 comments
-
Just to mention, the Java proposal uses a semicolon to terminate match arms: http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html Also following the argument regarding the trailing comma, it is most useful when you are "commenting" a case rather than "adding" a case. |
Beta Was this translation helpful? Give feedback.
-
For keywords, I would go for a when (e) (
is Mult(Const(0), var _) || is Mult(var _, Const(0)): Const(0),
is Mult(Const(1), var x) || is Mult(var x, Const(1)): Simplify(x),
is Mult(Const(var l), Const(var r)): Const(l*r),
is Add(Const(0), var x) || is Add(var x, Const(0)): Simplify(x),
is Add(Const(var l),(var r)): Const(l+r),
is Neg(Const(var k)) && k != 0: Const(-k),
else: e
) |
Beta Was this translation helpful? Give feedback.
-
I propose a very concise syntax resembling ternary expressions:
|
Beta Was this translation helpful? Give feedback.
-
I suspect you are too late with such proposals. If you take a look here at the latest code on the patterns branch, the following syntax compiles: var area = primitive switch {
Line l => (double?)0,
Rectangle r when r.Width == r.Height => r.Width * r.Height,
Circle c => Math.PI * c.Radius * c.Radius,
_ => null
}; I think (in fact, I hope, as I really like it) that this lambda syntax that @gafter is developing against will be the adopted syntax. |
Beta Was this translation helpful? Give feedback.
-
That syntax could be ambiguous with ternary expressions. |
Beta Was this translation helpful? Give feedback.
-
As with other operands too, you would have to use parentheses in certain cases. E.g., you must enclose a ternary expression used in string interpolation in parentheses or sometime a ternary expression used inside another ternary expression. Other than @gafter's variant, my syntax does neither use braces nor commas. My idea is to make a parallel to the 2 variants of the CASE-expression in SQL. Both look very similar. One uses conditions (comparable to ternary expressions), the other switches on a value. Therefore, my syntax resembles the one of ternary expressions. |
Beta Was this translation helpful? Give feedback.
-
@OJacot-Descombes What if the expression I am switching on is a double? area = match primitive
? 1 : 0
? Rectangle r when r.Width == r.Height: r.Width * r.Height
? Circle c: Math.PI * c.Radius * c.Radius
: null; |
Beta Was this translation helpful? Give feedback.
-
You need to precisely describe the precedence of the pieces of your expression for us to make sense of it. |
Beta Was this translation helpful? Give feedback.
-
Don't we have the same precedence problem today, when the condition of a ternary expression is another ternary expression? I would treat the match expression like a new kind of ternary expression and use the same precedence rules as for ternary expressions. Ternary example:
Note that the braces are not part of the proposed syntax of the match expression, but are there to modify the precedence of the terms. |
Beta Was this translation helpful? Give feedback.
-
@gafter commented on Wed Feb 17 2016
We need the LDM (C# language design meeting attendees) to decide what the syntax of a "match expression" should be, and then we need to implement that.
Are we using
switch
ormatch
?default:
orcase *:
or both?commas between cases?
Curly braces or parens?
Must a match expression be complete? If not, what happens when it isn't?
What about a single-case (irrefutable) match expression?
@gafter commented on Wed Feb 17 2016
@MadsTorgersen Can we meet sometime this week to make some tentative calls for the prototype?
@DavidArno commented on Wed Feb 17 2016
Not sure if you really want the opinions on non-LDM members here, but I'll offer them anyway (I assume it can be deleted if this is an unhelpful comment):
If
match
can be used in a non-breaking fashion, please use that. It'll make teaching the concept of match expressions to others easier if it has a different name toswitch
Please, please, please don't use
case *
. This closes off the option for using*
as a throw-away variable (the equivalent to F#'s_
) in later releases of C#.@HaloFour commented on Wed Feb 17 2016
Another peanut-gallery opinion, feel free to forward to
/dev/null
.I think I might prefer
match
toswitch
as it allows avoiding the baggage that may otherwise be inherited by reusingswitch
, even though the syntax and context would be quite different.I prefer
case *
todefault
for much of the same reason, although if you go withmatch
it probably doesn't matter much. I don't see why it would preclude the possibility of implementing a feature like #8074 in the future considering that the syntactic contexts are different.Does it make sense for an incomplete match in an expression to result in anything other than an exception? I'm not sure that it does. As such I think that the compiler should try to enforce that the match is complete and silently emit a wildcard pattern that throws unless one is already defined.
@alrz commented on Thu Feb 18 2016
I think I'd prefer
switch
instead ofmatch
as long as they feature similar possibilities. Currently as it is specified, it would be not possible to write multiple cases (anddefault
case) in theswitch
expression even though you have chosenswitch
to keep them closer, syntactically. Whilecase *
is something that would be expected in a pattern-matching construct, adefault
case is idiomatic C# and IMO shouldn't be excluded fromswitch
expression. I think it's more of a preference but it doesn't mean that one should be discarded in favor of the other.@gafter commented on Thu Feb 18 2016
The main reason that I resist
default:
in a match is that we want the match cases to be placed in order. In a switch statement, you can put thedefault
anywhere among the cases, but it always matches last. We want to force it to be last. But I suppose we could just require it to be in the last position only for a match expression.I think we're likely to change the keyword from
switch
to the contextual keywordmatch
for the match expression.@alrz commented on Thu Feb 18 2016
If it's likely to change the keyword to
match
, I can tell there would be no need for commas and case expressions can be represented bymatch <pattern>
which doesn't need to disallow chaining.Just a quick question, ordering problem doesn't apply to switch statement already? I mean the following would be useless, because
name
woudn't be definitely assigned anyway,Why it cannot be applied to match expressions as well?
@DavidArno commented on Thu Feb 18 2016
@gafter,
This surely has to apply to a match statement too? If the
switch
is using the new pattern-matching features, then it's a match statement and thus the order of the cases becomes important and thedefault
must therefore be last. This isn't just an issue for match expressions.@gafter commented on Thu Feb 18 2016
@DavidArno No, we're not going to change the fact that a
switch
statement treats thedefault
case as a "last fallback" no matter where it appears in the syntax. The addition of a pattern-matching construct somewhere in the switch won't change that.@alrz
I have no idea what this means. What syntax are you imagining?
@alrz commented on Thu Feb 18 2016
Becomes,
@DavidArno commented on Thu Feb 18 2016
@gafter,
So, taking the example from xxx:
I could change that to:
and it will not affect the functionality? Will
default
just be shifted to the end of the list by the compiler therefore? That will be highly confusing: "pattern matching switch statements test each case in order, stopping when a pattern matches, except fordefault
, which will be treated as the last expression, no matter where you put it in the list" That's nasty.@HaloFour commented on Thu Feb 18 2016
@DavidArno That's the baggage inherited from
switch
anddefault
. It could be argued that pattern matching doesn't fit well with the semantics ofswitch
considering that order is not supposed to matter. Maybematch
should be used for statement pattern matching also. Ditch the baggage altogether.@DavidArno commented on Thu Feb 18 2016
@HaloFour,
Yes, that's exactly what I'd like to see. The current switch statement is a wholly different thing to a match statement. So don't try and merge the two into some amorphous mess: make them two distinct things.
Further I'm sure that any breaking change concerns around using the match keyword will prove easier to solve than trying to make pattern matching work fully with goto and the like.
@gafter commented on Thu Feb 18 2016
@DavidArno Those are already the semantics of the existing
switch
: it treats the cases as if in order (since they cannot overlap, this is trivially so), exceptdefault
which is always handled last. The funny order ofdefault
is one of two slightly unfortunate effects of using the existing switch statement syntax for pattern-matching, the other being the treatment ofgoto case
. I would be fine adding a warning (or perhaps even an error) when adefault
appears anywhere but the last position in aswitch
that contains any pattern-matching syntax.@bondsbw commented on Thu Feb 18 2016
Would
match
provide exhaustive matching (except in the case thatcase *:
ordefault:
is provided)? And how would this be implemented, usingsealed
(to ensure it cannot be subclassed elsewhere)?I don't think I care for
match
unless it fundamentally provides value such as this. I would hate to use up that keyword and deny a future implementation that can properly guarantee exhaustive matching.@gafter commented on Thu Feb 18 2016
@bondsbw That is precisely the question asked in this issue (fifth question in the list).
@AdamSpeight2008 commented on Thu Feb 18 2016
match
gets my vote. (eg #5202)'default:
required in cases where compiler can prove completeness of the matches. If the compiler proves completeness and there is a
default:that section section of code is mark as
unreachable?or
unnecessary'.@bondsbw commented on Thu Feb 18 2016
@gafter Sorry I realized later that's what you meant by "complete", but I did want to throw my (perhaps unsolicited and humble) opinion in that non-exhaustive/incomplete matching isn't worth locking down a new keyword.
@JohnnyBravo75 commented on Mon Mar 21 2016
I vote for 'switch' because it is an already used construct in c#.
Its syntax is not the best, but its better to reuse it and give it more power with matching than introducing match as an extra keyword.
@AdamSpeight2008 commented on Mon Mar 21 2016
My concerns with using
switch
is that it changes the semantics of it, potentially break compatibility with existing code. Usingmatch
doesn't as well as indicating that this block is a pattern-match.@gafter commented on Mon Mar 21 2016
@AdamSpeight2008 We will not change the meaning of existing code. This issue is about a new syntactic form for an expression.
@AdamSpeight2008 commented on Mon Mar 21 2016
@gafter Say if I have pre-existing code using
switch
then recompile it with a compiler that usespattern-matching switch
. Would it compile to the same code, or different.@AdamSpeight2008 commented on Mon Mar 21 2016
The following would silently compile in
pattern-matching switch
compilerwhere as in existing compiler would fail.
@HaloFour commented on Mon Mar 21 2016
@AdamSpeight2008
That would not be a legal
switch
expression. Theswitch
keyword would be used as an operator following the operand. I also seriously doubt that an empty pattern list would be legal.A
switch
statement, on the other hand, cannot be assigned to a variable. You'd have to assign the variable within the case labels:@AdamSpeight2008 commented on Mon Mar 21 2016
@HaloFour
It for illustrative purposes, the original is saved with the pre-existing error. Yet opening it in a PMS compiler the pre-existing isn't an error.
@paulomorgado commented on Mon Mar 21 2016
@gafter, why is that so important that the default case be the last? Just to keep the semantics that they are enforced in order?
If it's not to expensive to have a special case
default:
when using pattern matching, I would stick with it.Have you tried analyzing real-life projects to see how often
default:
appears and it's not the last option?@HaloFour commented on Mon Mar 21 2016
@AdamSpeight2008
Well your example would most definitely be an error both pre- and post-pattern matching, but that's beside the point. Virtually every new feature results in previously non-compiling code to now compile. That's very explicitly not a breaking change. The fact that
switch
can't be used in some contexts in C# 6.0 doesn't mean that it can never be considered for use in those contexts in future versions. There is no example of pattern matchingswitch
, in statement or expression form, that would be considered legal code today.@HaloFour commented on Mon Mar 21 2016
@paulomorgado
I've seen it used where the developer wanted to keep the cases in order (by enum names or whatever) and the default behavior would be identical to one of the cases so they wanted to take advantage of fall-through rather than duplicate code:
This was never an issue previously as there was never any overlap between the cases and the comparisons were always very simple. Pattern matching will introduce the potential for overlap and user-defined evaluation which makes the order of evaluation important. Since the difference between a pre-pattern matching switch and a post-pattern matching switch is effectively just the introduction of a single case that could change the above code in unexpected ways, specifically
MyEnum.C
might never be evaluated since it comes after thedefault
case, although more likely it would be a compile-time error sinceMyEnum.C
is subsumed by thedefault
case.@paulomorgado commented on Mon Mar 21 2016
@HaloFour, those would be surprised to see that they can't place
default:
anywhere they want to when it cames to pattern matching, but their existing code wouldn't break,@AdamSpeight2008 commented on Mon Mar 21 2016
@HaloFour The confusion is that I see the patten-matching in functional languages as a function. Then the `return' being used to a value from it. In the current implementation (as is) the returned value is returned not the "pattern match" but the enclosing method.
I think we would have to do something like the following to replicate that.
I think we should consider would it be better to treat like a lambda function block.
@HaloFour commented on Mon Mar 21 2016
@AdamSpeight2008
Such syntax was already proposed and dismissed in #206, specifically the "hijacking" of the
return
statement. Fairly sure that's not on the table and that this issue is specifically to address the otherwise minor syntactic issues around implementing proposal #5154, or rather it's evolution since being absorbed by the greater pattern matching proposal.@alrz commented on Mon Mar 21 2016
@HaloFour
This is because you are assuming that
default
is a synonym forcase *
. But it's not (shouldn't be), for example,@HaloFour commented on Mon Mar 21 2016
@alrz
I agree,
default
shouldn't be synonymous withcase *
. Thedefault
case should be considered the last case regardless of where it appears in lexical order, thus retaining the behavior that it has today.I think that for
switch
statements bothdefault
andcase *
should be supported, but that they would be treated differently.default
could appear anywhere but would only be considered as the last option.case *
would be considered in lexical order with the other patterns, effectively meaning that it has to appear last:My opinion is also that the expression form should simply not support
default
that way it's not necessary to even consider how it differs behaviorally. I also prefermatch
overswitch
which I think will prevent developers from even expectingdefault
to be an option.@DavidArno commented on Mon Mar 21 2016
@AdamSpeight2008,
I think you may be confusing match statements with match expressions; the latter being the topic of this thread. A match expression will likely take one of the following two forms (depending on whether
match
orswitch
is chosen as the keyword:It's an expression, so you couldn't use
return
as that's a statement. The result of each case has to be a value; not one or more statements. Think of it like the ternary operator.@alrz commented on Mon Mar 21 2016
@HaloFour I don't see any reason why
match
shouldn't have multiple cases just likeswitch
, to prevent code duplication, that's wheredefault
comes in handy to also help to prevent it.@DavidArno commented on Mon Mar 21 2016
@alrz,
So you'd see the following being a valid
match
?@alrz commented on Mon Mar 21 2016
@DavidArno Exactly, now assume that you don't return
0
and don't have multiple cases,I think that is horrible.
@DavidArno commented on Mon Mar 21 2016
@alrz,
It occurs to me that either we haven't picked a good example, or we're overcomplicating it, as your code could be simplified to:
I'm not sure which it is though. Can you think of a better example? 😀
@alrz commented on Mon Mar 21 2016
@bondsbw commented on Mon Mar 21 2016
Same thing as
@DavidArno commented on Mon Mar 21 2016
@bondsbw,
No, that's not the same. With your example,
Foo(1)
would result ine2
.@alrz,
I really feel uncomfortable with that
default
, but can't really put my finger on why and it could indeed be useful. I think I'd prefer something like the following, but I'm not sure if it'll fit the spec:@alrz commented on Mon Mar 21 2016
@DavidArno I would not prefer any new syntax here, actually it is a good thing that it'd be similar to
switch
syntax as fordefault
andcase
labels. So you can simply rewrite yourswitch
as amatch
whenever it makes sense,So I don't see why it feels uncomfortable, because we already have code like this in
switch
.Anyhow, I'd be ok if this doesn't get implemented in C# 7 timeframe, because it is kind of related to #6235:
So that multiple cases behave like an OR pattern.
@DavidArno commented on Mon Mar 21 2016
Ah thanks, I thought it looked familiar and that was why I was uncomfortable with it. I'd far prefer
||
be used for OR patterns:To my mind, the less it looks like a
switch
, the better as I make no secret of the fact I positively hate theswitch
statement and what they plan to do with it when adding pattern matching. But, as you say, OR patterns are probably a debate for after C# 7 is released.@alrz commented on Mon Mar 21 2016
@DavidArno When you explicitly use an OR pattern you don't need to mention
case
keyword for the second time, because it would be defined under pattern andcase
is not part of that. See #6235.@gafter commented on Mon Mar 21 2016
@AdamSpeight2008
Same, plus or minus epsilon.
@alrz commented on Tue Mar 22 2016
I'd like to note that there is no other expressions that use parenteses and also support trailing commas,
So I think it would be more consistent if we use curly braces for
match
as long as we require comma between cases.In defense of tuples, if they ever support trailing commas that's because a oneple would be ambiguous with a parenthesized-expression, in any case, if you add more items you are practically changing the type; this is not true for
with
,match
or object initializers.@DavidArno commented on Tue Mar 22 2016
@alrz,
To keep it consistent, if braces were used, trailing commas would have to be supported too, which would mean extending that embarrassingly bad design decision into more languages features. So the best consistent option from your examples is parentheses with no trailing comma allowed.
@alrz commented on Tue Mar 22 2016
Trailing comma is an embarrassingly bad design decision. Noted.
@AdamSpeight2008 commented on Tue Mar 22 2016
The final trailing comma shouldn't be needed.
@alrz commented on Tue Mar 22 2016
You guys know that it's optional right? And I'm not proposing it, it is from spec draft.
@DavidArno commented on Wed Mar 23 2016
@alrz,
I'm aware it's optional; that's it's problem. When looking at a piece of code with a trailing comma, one must ask: is it there because the author likes to use them, because they forgot to refactor, or because something has been missed and thus it could be a bug. They create a serious hindrance to readability just to pander to developers who want their lives made fractionally easier when writing the code.
@alrz commented on Wed Mar 23 2016
@orthoxerox Do I need a sarcasm sign? 😄
@DavidArno Perhaps you should research why it is useful in the first place and why do we care about it (or not). This is nothing new in C# or programming language design overall. I don't think that I need to explain the basics. Again, I'm not proposing it and my suggestion is based on the current design (of C# not just
match
).@orthoxerox commented on Wed Mar 23 2016
@alrz Mornings are never kind to me 😪
I like both trailing commas and curlies.
@DavidArno commented on Wed Mar 23 2016
@alrz,
You may rest assured that I have researched it. There are three main use cases:
The first two are only of use to developers who value making their lives easier when writing code over making the lives of readers of their code, easier. The third doesn't really apply to 99.9%of C# developers.
Mistakes will always be made in designing languages and decisions taken 10-15 years ago will often be viewed as wrong with the benefit of hindsight. C# is a conservative language and avoids breaking changes. So we are stuck with trailing commas being supported for some existing features. That doesn't mean they should be used though. And "we have always done it like that" is a very silly reason to repeat those mistakes with new features.
Ergo, what C# currently does isn't important; doing
match
properly, is.@HaloFour commented on Wed Mar 23 2016
@DavidArno Being internally consistent is even more important. The syntax doesn't affect the behavior of
match
(orswitch
) in the least, this is a personal style choice. If you don't like it, you're free to both not use it and to write an analyzer which errors if it encounters it.@DavidArno commented on Wed Mar 23 2016
@HaloFour,
Consistency is important, so use
()
formatch
as the convention there is not to have trailing commas 😀@alrz commented on Wed Mar 23 2016
@DavidArno without comma it will be ambiguous with case expressions. There is a reason for every bit of the syntax. You should try to understand this.
@DavidArno commented on Wed Mar 23 2016
@alrz,
How would a trailing comma remove ambiguity?
@HaloFour commented on Wed Mar 23 2016
@DavidArno That works for me.
I'm kind of on the fence about the whole brace v. parenthesis bit. I think parenthesis looks fine for a handful of patterns but beyond that I think braces would look nicer. It's like how a method with a huge number of arguments can look awkward. But it's really a minor concern.
I'm much more concerned about the behavior and features of the expression than it's specific syntax. I'd be thrilled with guillemets and poop emojis if they delivered active patterns and proper AND/OR patterns.
@alrz commented on Fri Apr 22 2016
@DavidArno Oh you are talking about just the trailing comma. Well, that doesn't seem to be up for discussion here, it is about using commas or not at all. And if they prefer to not use it, perhaps they should redesign case expressions to be distinguishable from case labels.
@bondsbw commented on Wed Mar 23 2016
Braces are used in C# when the contents are typically expected to be provided on multiple lines. Parentheses are used otherwise.
And I believe that most code formatters make the assumption that parentheses are intended to span one line (assuming it's not too long). I made a fluent syntax for an area of my project that creates a hierarchical outline:
One annoyance is that Resharper wants to reformat the parentheses every time I edit anything, because in most other cases that's the expectation. I suspect other tooling would be similar.
So for match expressions, I feel braces are definitely more consistent than parentheses.
@AdamSpeight2008 commented on Wed Mar 23 2016
Didn't you say the comma was optional? Hence no abiquity.
-------- Original Message --------
From:David Arno [email protected]
Sent:Wed, 23 Mar 2016 14:29:53 +0000
To:dotnet/roslyn [email protected]
Cc:Adam Speight [email protected]
Subject:Re: [roslyn] Reconcile syntax of "match" expression based on LDM feedback (#8818)
@aluanhaddad commented on Thu Mar 31 2016
The phrase "hijacking the meaning of the return statement" is forever etched into my brain. I will never live it down 😝
If possible I would prefer that there be no delimiting
;
s or,
s between cases in a match expression. For one thing, consider that the presence of any;
tokens in a switch statement is incidental, they are not part of the syntax ofswitch
. For another, consider the syntax of the ternary operator.Additionally, I don't think Resharper's, or any tool's, code formatting behavior should impact this proposal.
Beta Was this translation helpful? Give feedback.
All reactions