C2 forum
General Category => Ideas => Topic started by: bas on March 27, 2014, 09:11:44 AM
-
Some new languages like C# changed the default behavior of a case statement so that it breaks by default.
I wonder if this would be an good for C2 as well. It would make writing case statements for concise, but we'd
need a keyword to specify fallthrough (fallthrough, next, ?). I currently lean to the default-break, unless there
are good arguments for default-fallthrough.
-
I'd suggest a third option: the user MUST terminate each case with a break or fallthrough (whatever keyword that may use) or return. Then there is no default, it is always explicit.
-
Nice one.
The choice would then be between more compact cases and more explicit code..
I also found another choice: In languages like Ada, there is a default break, but you
can specify more matches in single case. Something like:
switch (x) {
case 1|2: ..
case 3|4 ..
}
-
I like having multiple cases combined. It is a fairly common thing in protocols to see several values that do the same thing (often for support of older versions of a protocol, for instance).
Best,
Kyle
-
Following the principle of least surprise, DerSaidin's proposal makes a lot of sense.
The question is do we really want a new keyword such as fallthrough or fallthru? As an alternative to a new keyword, we could use the goto keyword with new semantics:
goto next; /* fall thru to the code below */
goto default; /* to branch to the default case */
goto case 'a'; /* to branch to the handler for 'a' */
Regarding combining multiple cases, it would be preferable to allow multiple case statements to follow one another without any intervening statement as this is the common idiom for C and it is widely used and poses no real problem. We could also extend the syntax for the case clause, but with operators that do not clash with current use: commas could be used to enumerate values, and a range operator could be introduced for to specify inclusive value ranges (.. seems an obvious choice for this).
-
switch (x) {
case 1|2: ..
case 3|4 ..
}
I agree with chqrlie that this would be better achieved by multiple case statements.
switch (x) {
case 1:
case 2:
...
break;
case 3:
case 4:
..
break;
}
(Note: imo, case 1 wouldn't require any explicit fallthrough because there is no code there to fallthrough from.)
I also agree that for the other option , would be a better separator than |.
-
Let me go a bit further:
There is no real reason why switch can't have more extended functionality:
1. Allow "case" to be followed by any expression
2. Allow switch to be without value
3. Compile "expression"-case to nested ifs, and regular values to normal switch/case.
E.g.
// (1) Compiles to if/else
switch
{
case (x > 0): do_something(); break;
case (y < 10): do_something_else(); break;
case (x + y < 1): foo(); break;
}
// (2) Compiles to if/else
switch (x)
{
case 0: zero_handle(); break;
case x > 0: do_something(); break;
case y < 10: do_something_else(); break;
case x + y < 1: foo(); break;
}
// (3) This compiles to switch/case
switch (x)
{
case 0: ... break;
case 1: ... break;
default: ... break;
}
To simplify, type (2) can be eliminated entirely. That also makes it clearer when we have possible jump tables and when not.
Compare case (1) with if/else:
switch
{
case (x > 0):
do_something();
break;
case (y < 10):
do_something_else();
break;
case (x + y < 1):
foo();
break;
}
if (x > 0) {
do_something();
} else if (y < 10) {
do_something_else();
} else of (x + y < 1) {
foo();
}
However, the "break" statement makes is a little less useful. In languages where "fallthrough" is required, this can be shortened further:
switch
{
case (x > 0):
do_something();
case (y < 10):
do_something_else();
case (x + y < 1):
foo();
}
A "break"-less switch would also allow for automatic scopes with each case. But that idea has to be refined a bit.
Anyway, just posting this as food for thought.
-
Also, it could be possible to provide both switch-with-fallthrough and switch-with-break by having two different syntax constructs, one with a new name, like "select (foo)" "match (foo)"
-
I thought of yet another way to do this:
- Introduce auto break like before create a ”fallthrough, empty case”
Maybe it could look like this:
switch (a) {
case 1 |
case 2 |
case 3:
foo();
case 4 |
case 5:
bar();
fallthrough;
case 6:
baz();
}
-
If there are first class strings, then switch on strings are is an awesome feature (likely implemented using a hash)
-
I think it's good to have a language as simple as possible. Especially to read. Having (the option) to specify whether
a switch statement is auto-break or auto-fallthrough is nasty when you are only seeing the case part on your screen.
You think it's auto-break, but it might be auto-fallthrough. All code/switch statements should just look alike.
Fallthrough (by forgetting a break) in C has been a common cause for bugs, so I think it should be addressed somehow.
My proposal would be to force either a break or fallthrough statement. But mapping this to generated C code might
not be trivial..
-
What did you think of
case 1 | case 2: foo(); above?
To clarify:
switch (a) {
case 1 | // Using : instead of | is syntax sugar for case 1: fallthrough;
case 2 |
case 3:
foo(); // With : we get a break;
case 4 |
case 5:
bar();
fallthrough; // If we want to execute a statement then pass to next.
case 6:
baz();
}
// The above in C:
switch (a) {
case 1:
case 2:
case 3:
foo();
break;
case 4:
case 5:
bar();
case 6:
baz();
break;
}
Another possibility is |: or :|
switch (foo) {
case 1|:
case 2|:
case 3:
do_something();
Using | means a that some care must be taken if there is an expression of type:
case 1|2: (This is is compiled to case 3: or course, but I think it's reasonable to require ( ) on any constant expression that isn't a literal.
So case 1+2: would not be allowed, but case (1+2): is ok.
-
I rather think that fallthrough is bad because it's so long to type :P
-
If you put a switch inside a while/for loop, continue currently means: jump to the next loop