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

Reconcile syntax of "match" expression based on LDM feedback #8818

Closed
gafter opened this Issue Feb 17, 2016 · 63 comments

Comments

@gafter
Member

gafter commented 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 or match?
default: or case *: 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

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Feb 17, 2016

Member

@MadsTorgersen Can we meet sometime this week to make some tentative calls for the prototype?

Member

gafter commented Feb 17, 2016

@MadsTorgersen Can we meet sometime this week to make some tentative calls for the prototype?

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno 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):

Are we using switch or match?

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 to switch

default: or case *: or both?

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#.

DavidArno commented 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):

Are we using switch or match?

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 to switch

default: or case *: or both?

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

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Feb 18, 2016

Another peanut-gallery opinion, feel free to forward to /dev/null.

I think I might prefer match to switch as it allows avoiding the baggage that may otherwise be inherited by reusing switch, even though the syntax and context would be quite different.

I prefer case * to default for much of the same reason, although if you go with match 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.

HaloFour commented Feb 18, 2016

Another peanut-gallery opinion, feel free to forward to /dev/null.

I think I might prefer match to switch as it allows avoiding the baggage that may otherwise be inherited by reusing switch, even though the syntax and context would be quite different.

I prefer case * to default for much of the same reason, although if you go with match 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

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Feb 18, 2016

Contributor

I think I'd prefer switch instead of match as long as they feature similar possibilities. Currently as it is specified, it would be not possible to write multiple cases (and default case) in the switch expression even though you have chosen switch to keep them closer, syntactically. While case * is something that would be expected in a pattern-matching construct, a default case is idiomatic C# and IMO shouldn't be excluded from switch expression. I think it's more of a preference but it doesn't mean that one should be discarded in favor of the other.

Contributor

alrz commented Feb 18, 2016

I think I'd prefer switch instead of match as long as they feature similar possibilities. Currently as it is specified, it would be not possible to write multiple cases (and default case) in the switch expression even though you have chosen switch to keep them closer, syntactically. While case * is something that would be expected in a pattern-matching construct, a default case is idiomatic C# and IMO shouldn't be excluded from switch 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

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Feb 18, 2016

Member

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 the default 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 keyword match for the match expression.

Member

gafter commented 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 the default 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 keyword match for the match expression.

@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Feb 18, 2016

Contributor

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 by match <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,

switch(...) {
  default:
  case Student(var name):
    break;
}

Why it cannot be applied to match expressions as well?

Contributor

alrz commented 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 by match <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,

switch(...) {
  default:
  case Student(var name):
    break;
}

Why it cannot be applied to match expressions as well?

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Feb 18, 2016

@gafter,

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 the default 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.

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 the default must therefore be last. This isn't just an issue for match expressions.

DavidArno commented Feb 18, 2016

@gafter,

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 the default 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.

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 the default must therefore be last. This isn't just an issue for match expressions.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Feb 18, 2016

Member

@DavidArno No, we're not going to change the fact that a switch statement treats the default 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

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 by match which doesn't need to disallow chaining.

I have no idea what this means. What syntax are you imagining?

Member

gafter commented Feb 18, 2016

@DavidArno No, we're not going to change the fact that a switch statement treats the default 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

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 by match which doesn't need to disallow chaining.

I have no idea what this means. What syntax are you imagining?

@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Feb 18, 2016

Contributor
// as originally proposed
var result = t match(case P1: e1 case P2: e2); // no comma

var result = t match P : e;
// instead of
var result = t case P : e;

case-expression:
shift-expression case pattern : shift-expression

Becomes,

case-expression:
relational-expression match pattern : shift-expression

Contributor

alrz commented Feb 18, 2016

// as originally proposed
var result = t match(case P1: e1 case P2: e2); // no comma

var result = t match P : e;
// instead of
var result = t case P : e;

case-expression:
shift-expression case pattern : shift-expression

Becomes,

case-expression:
relational-expression match pattern : shift-expression

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Feb 18, 2016

@gafter,

So, taking the example from xxx:

switch (e) {
    case Mult(Const(0), *): return Const(0);
    case Mult(*, Const(0)): return Const(0);
    case Mult(Const(1), var x): return Simplify(x);
    case Mult(var x, Const(1)): return Simplify(x);
    case Mult(Const(var l), Const(var r)): return Const(l*r);
    case Add(Const(0), var x): return Simplify(x);
    case Add(var x, Const(0)): return Simplify(x);
    case Add(Const(var l), Const(var r)): return Const(l+r);
    case Neg(Const(var k)): return Const(-k);
    default: return e;
  }

I could change that to:

switch (e) {
    case Mult(Const(0), *): return Const(0);
    default: return e;
    case Mult(*, Const(0)): return Const(0);
    case Mult(Const(1), var x): return Simplify(x);
    case Mult(var x, Const(1)): return Simplify(x);
    case Mult(Const(var l), Const(var r)): return Const(l*r);
    case Add(Const(0), var x): return Simplify(x);
    case Add(var x, Const(0)): return Simplify(x);
    case Add(Const(var l), Const(var r)): return Const(l+r);
    case Neg(Const(var k)): return Const(-k);
  }

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 for default, which will be treated as the last expression, no matter where you put it in the list" That's nasty.

DavidArno commented Feb 18, 2016

@gafter,

So, taking the example from xxx:

switch (e) {
    case Mult(Const(0), *): return Const(0);
    case Mult(*, Const(0)): return Const(0);
    case Mult(Const(1), var x): return Simplify(x);
    case Mult(var x, Const(1)): return Simplify(x);
    case Mult(Const(var l), Const(var r)): return Const(l*r);
    case Add(Const(0), var x): return Simplify(x);
    case Add(var x, Const(0)): return Simplify(x);
    case Add(Const(var l), Const(var r)): return Const(l+r);
    case Neg(Const(var k)): return Const(-k);
    default: return e;
  }

I could change that to:

switch (e) {
    case Mult(Const(0), *): return Const(0);
    default: return e;
    case Mult(*, Const(0)): return Const(0);
    case Mult(Const(1), var x): return Simplify(x);
    case Mult(var x, Const(1)): return Simplify(x);
    case Mult(Const(var l), Const(var r)): return Const(l*r);
    case Add(Const(0), var x): return Simplify(x);
    case Add(var x, Const(0)): return Simplify(x);
    case Add(Const(var l), Const(var r)): return Const(l+r);
    case Neg(Const(var k)): return Const(-k);
  }

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 for default, which will be treated as the last expression, no matter where you put it in the list" That's nasty.

@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Feb 18, 2016

@DavidArno That's the baggage inherited from switch and default. It could be argued that pattern matching doesn't fit well with the semantics of switch considering that order is not supposed to matter. Maybe match should be used for statement pattern matching also. Ditch the baggage altogether.

HaloFour commented Feb 18, 2016

@DavidArno That's the baggage inherited from switch and default. It could be argued that pattern matching doesn't fit well with the semantics of switch considering that order is not supposed to matter. Maybe match should be used for statement pattern matching also. Ditch the baggage altogether.

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno 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.

DavidArno commented 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

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Feb 18, 2016

Member

@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), except default which is always handled last. The funny order of default is one of two slightly unfortunate effects of using the existing switch statement syntax for pattern-matching, the other being the treatment of goto case. I would be fine adding a warning (or perhaps even an error) when a default appears anywhere but the last position in a switch that contains any pattern-matching syntax.

Member

gafter commented 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), except default which is always handled last. The funny order of default is one of two slightly unfortunate effects of using the existing switch statement syntax for pattern-matching, the other being the treatment of goto case. I would be fine adding a warning (or perhaps even an error) when a default appears anywhere but the last position in a switch that contains any pattern-matching syntax.

@bondsbw

This comment has been minimized.

Show comment
Hide comment
@bondsbw

bondsbw Feb 18, 2016

Would match provide exhaustive matching (except in the case that case *: or default: is provided)? And how would this be implemented, using sealed (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.

bondsbw commented Feb 18, 2016

Would match provide exhaustive matching (except in the case that case *: or default: is provided)? And how would this be implemented, using sealed (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 gafter self-assigned this Feb 18, 2016

@gafter gafter added this to the 2.0 (Preview) milestone Feb 18, 2016

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Feb 18, 2016

Member

@bondsbw That is precisely the question asked in this issue (fifth question in the list).

Member

gafter commented Feb 18, 2016

@bondsbw That is precisely the question asked in this issue (fifth question in the list).

@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Feb 18, 2016

Contributor

match gets my vote. (eg #5202)

match ( e )
{

 |: Mult(Const(0), *),
    Mult(*, Const(0)) => Const(0);

 |: Mult(Const(1), var x),
    Mult(var x, Const(1)) => Simplify(x);

 |: Mult(Const(var l), Const(var r)) => Const(l*r);

 |: Add(Const(0), var x),
    Add(var x, Const(0)) => Simplify(x);

 |: Add(Const(var l), Const(var r)) => Const(l+r);

 |: Neg(Const(var k)) => Const(-k);

 default:
   return e;
}

'default:required in cases where compiler can prove completeness of the matches. If the compiler proves completeness and there is adefault:that section section of code is mark asunreachable?orunnecessary'.

Contributor

AdamSpeight2008 commented Feb 18, 2016

match gets my vote. (eg #5202)

match ( e )
{

 |: Mult(Const(0), *),
    Mult(*, Const(0)) => Const(0);

 |: Mult(Const(1), var x),
    Mult(var x, Const(1)) => Simplify(x);

 |: Mult(Const(var l), Const(var r)) => Const(l*r);

 |: Add(Const(0), var x),
    Add(var x, Const(0)) => Simplify(x);

 |: Add(Const(var l), Const(var r)) => Const(l+r);

 |: Neg(Const(var k)) => Const(-k);

 default:
   return e;
}

'default:required in cases where compiler can prove completeness of the matches. If the compiler proves completeness and there is adefault:that section section of code is mark asunreachable?orunnecessary'.

@bondsbw

This comment has been minimized.

Show comment
Hide comment
@bondsbw

bondsbw 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.

bondsbw commented 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.

@gafter gafter added the 0 - Backlog label Feb 24, 2016

@gafter gafter modified the milestones: 2.0 (RC), 2.0 (Preview) Feb 25, 2016

@JohnnyBravo75

This comment has been minimized.

Show comment
Hide comment
@JohnnyBravo75

JohnnyBravo75 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.

JohnnyBravo75 commented 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

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Mar 21, 2016

Contributor

My concerns with using switch is that it changes the semantics of it, potentially break compatibility with existing code. Using match doesn't as well as indicating that this block is a pattern-match.

Contributor

AdamSpeight2008 commented Mar 21, 2016

My concerns with using switch is that it changes the semantics of it, potentially break compatibility with existing code. Using match doesn't as well as indicating that this block is a pattern-match.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Mar 21, 2016

Member

@AdamSpeight2008 We will not change the meaning of existing code. This issue is about a new syntactic form for an expression.

Member

gafter commented 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

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Mar 21, 2016

Contributor

@gafter Say if I have pre-existing code using switch then recompile it with a compiler that uses pattern-matching switch. Would it compile to the same code, or different.

Contributor

AdamSpeight2008 commented Mar 21, 2016

@gafter Say if I have pre-existing code using switch then recompile it with a compiler that uses pattern-matching switch. Would it compile to the same code, or different.

@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Mar 21, 2016

Contributor

The following would silently compile in pattern-matching switch compiler

x = switch ( )
    {
    }

where as in existing compiler would fail.

Contributor

AdamSpeight2008 commented Mar 21, 2016

The following would silently compile in pattern-matching switch compiler

x = switch ( )
    {
    }

where as in existing compiler would fail.

@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Mar 21, 2016

@AdamSpeight2008

That would not be a legal switch expression. The switch keyword would be used as an operator following the operand. I also seriously doubt that an empty pattern list would be legal.

var result = operand switch (case Foo: "Foo" case Bar: "Bar" case *: "Other");

A switch statement, on the other hand, cannot be assigned to a variable. You'd have to assign the variable within the case labels:

string result;
switch (operand) {
    case Foo:
        result = "Foo";
        break;
    case Bar:
        result = "Bar";
        break;
    default:
        result = "Other";
        break;
}

HaloFour commented Mar 21, 2016

@AdamSpeight2008

That would not be a legal switch expression. The switch keyword would be used as an operator following the operand. I also seriously doubt that an empty pattern list would be legal.

var result = operand switch (case Foo: "Foo" case Bar: "Bar" case *: "Other");

A switch statement, on the other hand, cannot be assigned to a variable. You'd have to assign the variable within the case labels:

string result;
switch (operand) {
    case Foo:
        result = "Foo";
        break;
    case Bar:
        result = "Bar";
        break;
    default:
        result = "Other";
        break;
}
@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Mar 21, 2016

Contributor

@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.

Contributor

AdamSpeight2008 commented 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

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado 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?

paulomorgado commented 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

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour 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 matching switch, in statement or expression form, that would be considered legal code today.

HaloFour commented 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 matching switch, in statement or expression form, that would be considered legal code today.

@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour 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:

switch (x) {
    case MyEnum.A:
        // ...
        break;
    case MyEnum.B:
    default:
        // ...
        break;
    case MyEnum.C:
        // ...
        break;
}

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 the default case, although more likely it would be a compile-time error since MyEnum.C is subsumed by the default case.

HaloFour commented 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:

switch (x) {
    case MyEnum.A:
        // ...
        break;
    case MyEnum.B:
    default:
        // ...
        break;
    case MyEnum.C:
        // ...
        break;
}

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 the default case, although more likely it would be a compile-time error since MyEnum.C is subsumed by the default case.

@paulomorgado

This comment has been minimized.

Show comment
Hide comment
@paulomorgado

paulomorgado 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,

paulomorgado commented 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

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Mar 21, 2016

Contributor

@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.

string result = ()=>{
  switch (operand)
  {
    case Foo:  return "Foo";
    case Bar:  return "Bar";
     default:  return "Other";
  }();
}

I think we should consider would it be better to treat like a lambda function block.

string result = switch (operand)
  {
    case Foo:  return "Foo";
    case Bar:  return "Bar";
     default:  return "Other";
  };
}
Contributor

AdamSpeight2008 commented 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.

string result = ()=>{
  switch (operand)
  {
    case Foo:  return "Foo";
    case Bar:  return "Bar";
     default:  return "Other";
  }();
}

I think we should consider would it be better to treat like a lambda function block.

string result = switch (operand)
  {
    case Foo:  return "Foo";
    case Bar:  return "Bar";
     default:  return "Other";
  };
}
@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour 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.

HaloFour commented 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

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 21, 2016

Contributor

@HaloFour

This was never an issue previously as there was never any overlap between the cases and the comparisons were always very simple.

This is because you are assuming that default is a synonym for case *. But it's not (shouldn't be), for example,

switch(expr) {
  case *: break;
  case Const(0): break; // ERROR: subsumption: previous case convers all the possible values 
  case Mult(var value, 0): break;
}

switch(expr) {
  default:
  case Const(0): /* (1) */ break; // perfectly fine, when expr is Const and otherwise 
  case Mult(var value, 0): break;
}

// in contrast, if you have to put the default at the end you must duplicate the (1) in both cases,
switch(expr) {
  case Const(0): /* (1) */ break; // when expr is Const
  case Mult(var value, 0): break; // when expr is Mult
  default: /* again (1) */ break; // otherwise -- this is where default and case star are the same
}

// and of course
switch(expr) {
  default:
  case Const(var value): break; // ERROR: value is not definitely assigned
}
Contributor

alrz commented Mar 21, 2016

@HaloFour

This was never an issue previously as there was never any overlap between the cases and the comparisons were always very simple.

This is because you are assuming that default is a synonym for case *. But it's not (shouldn't be), for example,

switch(expr) {
  case *: break;
  case Const(0): break; // ERROR: subsumption: previous case convers all the possible values 
  case Mult(var value, 0): break;
}

switch(expr) {
  default:
  case Const(0): /* (1) */ break; // perfectly fine, when expr is Const and otherwise 
  case Mult(var value, 0): break;
}

// in contrast, if you have to put the default at the end you must duplicate the (1) in both cases,
switch(expr) {
  case Const(0): /* (1) */ break; // when expr is Const
  case Mult(var value, 0): break; // when expr is Mult
  default: /* again (1) */ break; // otherwise -- this is where default and case star are the same
}

// and of course
switch(expr) {
  default:
  case Const(var value): break; // ERROR: value is not definitely assigned
}
@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 21, 2016

Contributor
var x = expr match(
    default:
    case Foo(1): e1,
    case Foo(var value): e2,
);


var x = expr match(
    case Foo(1): e1,
    case Foo(var value): e2,
    case *: e1,
);
Contributor

alrz commented Mar 21, 2016

var x = expr match(
    default:
    case Foo(1): e1,
    case Foo(var value): e2,
);


var x = expr match(
    case Foo(1): e1,
    case Foo(var value): e2,
    case *: e1,
);
@bondsbw

This comment has been minimized.

Show comment
Hide comment
@bondsbw

bondsbw Mar 21, 2016

Same thing as

var x = expr match(
    case Foo(var value): e2,
    case *: e1,
);

bondsbw commented Mar 21, 2016

Same thing as

var x = expr match(
    case Foo(var value): e2,
    case *: e1,
);
@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Mar 21, 2016

@bondsbw,

No, that's not the same. With your example, Foo(1) would result in e2.

@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:

var x = expr match(
    case Foo(1) || default: e1,
    case Foo(var value): e2
);

DavidArno commented Mar 21, 2016

@bondsbw,

No, that's not the same. With your example, Foo(1) would result in e2.

@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:

var x = expr match(
    case Foo(1) || default: e1,
    case Foo(var value): e2
);
@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 21, 2016

Contributor

@DavidArno I would not prefer any new syntax here, actually it is a good thing that it'd be similar to switch syntax as for default and case labels. So you can simply rewrite your switch as a match whenever it makes sense,

T value;
switch(...) {
  case ...:
  case ...:
    value = foo;
    break;
  case ...:
    value = bar;
    break;
}

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:

// example from pattern spec

Expr Simplify(Expr e) => e match(
    case Mult(Const(0), *):
    case Mult(*, Const(0)): Const(0),
    case Mult(Const(1), var x): 
    case Mult(var x, Const(1)): Simplify(x),
    case Mult(Const(var l), Const(var r)): Const(l*r),
    case Add(Const(0), var x):
    case Add(var x, Const(0)): Simplify(x),
    case Add(Const(var l), Const(var r)): Const(l+r),
    case Neg(Const(var k)): Const(-k),
    default: e
);

So that multiple cases behave like an OR pattern.

Contributor

alrz commented 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 for default and case labels. So you can simply rewrite your switch as a match whenever it makes sense,

T value;
switch(...) {
  case ...:
  case ...:
    value = foo;
    break;
  case ...:
    value = bar;
    break;
}

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:

// example from pattern spec

Expr Simplify(Expr e) => e match(
    case Mult(Const(0), *):
    case Mult(*, Const(0)): Const(0),
    case Mult(Const(1), var x): 
    case Mult(var x, Const(1)): Simplify(x),
    case Mult(Const(var l), Const(var r)): Const(l*r),
    case Add(Const(0), var x):
    case Add(var x, Const(0)): Simplify(x),
    case Add(Const(var l), Const(var r)): Const(l+r),
    case Neg(Const(var k)): Const(-k),
    default: e
);

So that multiple cases behave like an OR pattern.

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno 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:

Expr Simplify(Expr e) => e match(
    case Mult(Const(0), *) || case Mult(*, Const(0)): Const(0),
    case Mult(Const(1), var x) || case Mult(var x, Const(1)): Simplify(x),
    case Mult(Const(var l), Const(var r)): Const(l*r),
    case Add(Const(0), var x) || case Add(var x, Const(0)): Simplify(x),
    case Add(Const(var l), Const(var r)): Const(l+r),
    case Neg(Const(var k)): Const(-k),
    default: e
);

To my mind, the less it looks like a switch, the better as I make no secret of the fact I positively hate the switch 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.

DavidArno commented 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:

Expr Simplify(Expr e) => e match(
    case Mult(Const(0), *) || case Mult(*, Const(0)): Const(0),
    case Mult(Const(1), var x) || case Mult(var x, Const(1)): Simplify(x),
    case Mult(Const(var l), Const(var r)): Const(l*r),
    case Add(Const(0), var x) || case Add(var x, Const(0)): Simplify(x),
    case Add(Const(var l), Const(var r)): Const(l+r),
    case Neg(Const(var k)): Const(-k),
    default: e
);

To my mind, the less it looks like a switch, the better as I make no secret of the fact I positively hate the switch 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

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 21, 2016

Contributor

@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 and case is not part of that. See #6235.

Contributor

alrz commented 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 and case is not part of that. See #6235.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Mar 22, 2016

Member

@AdamSpeight2008

@gafter Say if I have pre-existing code using switch then recompile it with a compiler that uses pattern-matching switch. Would it compile to the same code, or different.

Same, plus or minus epsilon.

Member

gafter commented Mar 22, 2016

@AdamSpeight2008

@gafter Say if I have pre-existing code using switch then recompile it with a compiler that uses pattern-matching switch. Would it compile to the same code, or different.

Same, plus or minus epsilon.

@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 22, 2016

Contributor

I'd like to note that there is no other expressions that use parenteses and also support trailing commas,

// record declaration - parens and no trailing comma
class Person(
  string FirstName,
  string LastName
);

// constructor and invocations, parens and no trailing comma
object F() => new Person(
  "FirstName",
  "LastName"
);

// initializer --  curly braces, trailing comma
object F() => new Foo {
  Bar = value,
};

// with --  curly braces, trailing comma
object F(Person person) => person with {
  FirstName = "FirstName",
  LastName = "LastName",
};

// match -- curly braces, trailing comma
object F(object arg) => arg match { 
  case Foo: expr,
  case Bar: expr,
};

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.

Contributor

alrz commented Mar 22, 2016

I'd like to note that there is no other expressions that use parenteses and also support trailing commas,

// record declaration - parens and no trailing comma
class Person(
  string FirstName,
  string LastName
);

// constructor and invocations, parens and no trailing comma
object F() => new Person(
  "FirstName",
  "LastName"
);

// initializer --  curly braces, trailing comma
object F() => new Foo {
  Bar = value,
};

// with --  curly braces, trailing comma
object F(Person person) => person with {
  FirstName = "FirstName",
  LastName = "LastName",
};

// match -- curly braces, trailing comma
object F(object arg) => arg match { 
  case Foo: expr,
  case Bar: expr,
};

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

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno 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.

DavidArno commented 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

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 22, 2016

Contributor

Trailing comma is an embarrassingly bad design decision. Noted.

Contributor

alrz commented Mar 22, 2016

Trailing comma is an embarrassingly bad design decision. Noted.

@AdamSpeight2008

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Mar 22, 2016

Contributor

The final trailing comma shouldn't be needed.

Contributor

AdamSpeight2008 commented Mar 22, 2016

The final trailing comma shouldn't be needed.

@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 22, 2016

Contributor

You guys know that it's optional right? And I'm not proposing it, it is from spec draft.

Contributor

alrz commented Mar 22, 2016

You guys know that it's optional right? And I'm not proposing it, it is from spec draft.

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno 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.

DavidArno commented 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

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 23, 2016

Contributor

@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).

Contributor

alrz commented 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

This comment has been minimized.

Show comment
Hide comment
@orthoxerox

orthoxerox Mar 23, 2016

Contributor

@alrz Mornings are never kind to me 😪

I like both trailing commas and curlies.

Contributor

orthoxerox commented Mar 23, 2016

@alrz Mornings are never kind to me 😪

I like both trailing commas and curlies.

@DavidArno

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Mar 23, 2016

@alrz,

You may rest assured that I have researched it. There are three main use cases:

  1. It makes it easier to write and edit lists of data;
  2. It makes it easier to write code generators;
  3. It makes it easier to view source change diffs using command line tools.

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.

DavidArno commented Mar 23, 2016

@alrz,

You may rest assured that I have researched it. There are three main use cases:

  1. It makes it easier to write and edit lists of data;
  2. It makes it easier to write code generators;
  3. It makes it easier to view source change diffs using command line tools.

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

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour Mar 23, 2016

@DavidArno Being internally consistent is even more important. The syntax doesn't affect the behavior of match (or switch) 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.

HaloFour commented Mar 23, 2016

@DavidArno Being internally consistent is even more important. The syntax doesn't affect the behavior of match (or switch) 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

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Mar 23, 2016

@HaloFour,

Consistency is important, so use () for match as the convention there is not to have trailing commas 😀

DavidArno commented Mar 23, 2016

@HaloFour,

Consistency is important, so use () for match as the convention there is not to have trailing commas 😀

@alrz

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 23, 2016

Contributor

@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.

Contributor

alrz commented 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

This comment has been minimized.

Show comment
Hide comment
@DavidArno

DavidArno Mar 23, 2016

@alrz,

How would a trailing comma remove ambiguity?

DavidArno commented Mar 23, 2016

@alrz,

How would a trailing comma remove ambiguity?

@HaloFour

This comment has been minimized.

Show comment
Hide comment
@HaloFour

HaloFour 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.

HaloFour commented 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

This comment has been minimized.

Show comment
Hide comment
@alrz

alrz Mar 23, 2016

Contributor

@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.

case_expression
-     : shift_expression 'case' pattern ':' shift_expression
+     : relational_expression 'match' pattern ':' shift_expression
      ;
Contributor

alrz commented Mar 23, 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.

case_expression
-     : shift_expression 'case' pattern ':' shift_expression
+     : relational_expression 'match' pattern ':' shift_expression
      ;
@bondsbw

This comment has been minimized.

Show comment
Hide comment
@bondsbw

bondsbw 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:

TableOfContents._
(
    BeforeYouBegin,
    Introduction,
    CompilerConcepts._
    (
        Lexer,
        Parser,
        Checker,
        Emitter
    ),
    CreatingYourOwnLanguage._
    (
        Design,
        Optimization,
        Tooling
    )
);

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.

bondsbw commented 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:

TableOfContents._
(
    BeforeYouBegin,
    Introduction,
    CompilerConcepts._
    (
        Lexer,
        Parser,
        Checker,
        Emitter
    ),
    CreatingYourOwnLanguage._
    (
        Design,
        Optimization,
        Tooling
    )
);

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

This comment has been minimized.

Show comment
Hide comment
@AdamSpeight2008

AdamSpeight2008 Mar 23, 2016

Contributor

Didn't you say the comma was optional? Hence no abiquity.

-------- Original Message --------
From:David Arno notifications@github.com
Sent:Wed, 23 Mar 2016 14:29:53 +0000
To:dotnet/roslyn roslyn@noreply.github.com
Cc:Adam Speight adam.speight@virgin.net
Subject:Re: [roslyn] Reconcile syntax of "match" expression based on LDM feedback (#8818)

@alrz,

How would a trailing comma remove ambiguity?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub

Contributor

AdamSpeight2008 commented Mar 23, 2016

Didn't you say the comma was optional? Hence no abiquity.

-------- Original Message --------
From:David Arno notifications@github.com
Sent:Wed, 23 Mar 2016 14:29:53 +0000
To:dotnet/roslyn roslyn@noreply.github.com
Cc:Adam Speight adam.speight@virgin.net
Subject:Re: [roslyn] Reconcile syntax of "match" expression based on LDM feedback (#8818)

@alrz,

How would a trailing comma remove ambiguity?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub

@aluanhaddad

This comment has been minimized.

Show comment
Hide comment
@aluanhaddad

aluanhaddad Apr 1, 2016

Such syntax was already proposed and dismissed in #206, specifically the "hijacking" of the return statement.

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 of switch. 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.

aluanhaddad commented Apr 1, 2016

Such syntax was already proposed and dismissed in #206, specifically the "hijacking" of the return statement.

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 of switch. 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.

@gafter

This comment has been minimized.

Show comment
Hide comment
@gafter

gafter Apr 21, 2017

Member

Issue moved to dotnet/csharplang #487 via ZenHub

Member

gafter commented Apr 21, 2017

Issue moved to dotnet/csharplang #487 via ZenHub

@gafter gafter removed this from Future Subfeatures in Compiler: Pattern-Matching Nov 17, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment