Closed lachbaer closed 6 years ago
It's not really "ternary" anymore if it's not composed of three parts.
So let's say you have code like this today:
int x;
switch (v)
{
case 0:
x = 10;
break;
case -1:
x = 37;
break;
case 5:
x = 99;
break;
default:
x = default(int);
break;
}
The above code is equivalent to the following:
int x =
v == 0 ? 10 :
v == -1 ? 37 :
v == 5 ? 99 :
default(int);
The question is, is the following syntax, using a proposed modified form of switch/case desirable and have any benefit:
int x = switch (v)
case 0: 10
case -1: 37
case 5: 99
Note the implied default
case.
The question is, is the following syntax, using a proposed modified form of switch/case desirable and have any benefit
That syntax form has the "dangling else" problem in a pretty bad way when switch expressions are nested.
Can't the "dangling else" problem be solved by convention, by saying it will take a greedy path or something like that, or is that because C# can't introduce ambiguous aspects in its grammar?
If you had code such as this:
int x = switch (v)
case 0: 10
case -1: switch (w) case 55: 5 case 66: 6 case 77: 7
case 5: 99
You can assume that the case 5: 99
is part of the switch (w)
, unless you wrote it like so:
int x = switch (v)
case 0: 10
case -1: (switch (w) case 55: 5 case 66: 6 case 77: 7)
case 5: 99
I'm guessing that you're saying this will break something??
@kasajian Yes, the something it will break is user's brains. We should avoid ambiguities in the language, as that is likely to result in broken user expectations.
As far as user's brain is concerned, doesn't that currently happen now?
int x = 0;
....
if (x == 0) x = 10; if (x == 1) x = 11; else x = 20;
Where does the else go with? The first if
or the second if
?
I think the canonical example is to leave out the x = 10;
.
I just Googled, and this language seems to be doing this: https://ceylon-lang.org/documentation/reference/expression/switch/
Looks pretty clear to me.
@kasajian Yes, that is an issue we inherited from C. That is one reason we discourage the controlled statement from being written without curly braces. But for the match expression, we don't inherit anything from C.
@lachbaer I think the real issue is deciding if this short version is to be an expression, with no worries of a dangling clause, or a statement, witch needs a way to handle dangling.
I think if your going to make a modern short syntax then an expression is required and following the ternary idea has great merit. It removes the need to have assignment in each clause, and the token required to separate it. The "test" needs to allow for decomposition also. var ans = (obj1, obj2) ? obj1==test1 => ans1, obj1== && obj2 == test2 => ans2, = defaultAns;
var answer = (obj1, obj2) ? obj1==test1 => ans1, obj1== && obj2 == test2 => ans2, = defaultAns;
The current proposal is the following:
var area = shape switch {
Line l => 0,
Rectangle r => r.Width * r.Height,
Circle c => Math.PI * c.Radius * c.Radius,
_ => throw new IllegalArgumentException()
};
The syntax is still open to possible change, and will be discussed in future LDM sessions.
Closing as discussion on this issue seems to have calmed down.
@gafter Just wonder what if we make a block with only one case and default, would it be any difference in performance than if/else
?
var area = shape switch {
Rectangle r => r.Width * r.Height,
default => 0
};
// vs
var area = 0;
if(shape is Rectangle r)
area = r.Width * r.Height;
ps. I would like the real syntax to be default
instead of _
@Thaina I would expect identical performance.
We do not use default
for a few reasons:
default
expression, and having a default
pattern would be ambiguous.default
case in a switch statement is always treated as a fall-back, only to be used if no other cases match, no matter where it appeared in the order of the cases. But the discard pattern _
is matched, like all patterns, in the order in which it appeared. To avoid confusion with the different behavior in a switch statement, we avoid a similar syntax.
I recently had an idea for a less verbose version of a
switch
('match') expression. It resembles the classical ternary operator with? :
There are three major differences.
case
operator before the?
makes this first expression a case expression instead of a boolean.?
and the first:
is nothing but whitespace:
without a preceeding comma or soBecause the expressions return a value (or throw) I chose the
=>
token to seperate the pattern from the following expression. But this, like all the rest of course, is up to discussion.