Author Topic: Switch statement  (Read 26108 times)

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Switch statement
« 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.

DerSaidin

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Switch statement
« Reply #1 on: April 11, 2014, 04:05:09 PM »
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.

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Re: Switch statement
« Reply #2 on: April 14, 2014, 09:28:11 AM »
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 ..
}
« Last Edit: April 14, 2014, 09:37:52 AM by bas »

kyle

  • Newbie
  • *
  • Posts: 48
    • View Profile
Re: Switch statement
« Reply #3 on: June 20, 2014, 11:07:17 PM »
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

chqrlie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Switch statement
« Reply #4 on: August 29, 2015, 11:50:08 PM »
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).

DerSaidin

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Switch statement
« Reply #5 on: August 30, 2015, 03:12:25 PM »
switch (x) {
case 1|2: ..
case 3|4 ..
}

I agree with chqrlie that this would be better achieved by multiple case statements.

Code: [Select]
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 |.

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Switch statement
« Reply #6 on: October 26, 2018, 11:34:34 PM »
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.

Code: [Select]
// (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:
Code: [Select]
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:

Code: [Select]
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.

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Switch statement
« Reply #7 on: October 29, 2018, 01:45:02 AM »
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)"

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Switch statement
« Reply #8 on: October 29, 2018, 08:38:47 AM »
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:

Code: [Select]
switch (a) {
  case 1 |
  case 2 |
  case 3:
     foo();
  case 4 |
  case 5:
     bar();
     fallthrough;
  case 6:
     baz();
}

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Switch statement
« Reply #9 on: November 01, 2018, 01:51:14 AM »
If there are first class strings, then switch on strings are is an awesome feature (likely implemented using a hash)

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Re: Switch statement
« Reply #10 on: November 08, 2018, 11:07:13 AM »
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..

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Switch statement
« Reply #11 on: November 08, 2018, 05:06:52 PM »
What did you think of

case 1 | case 2: foo(); above?

To clarify:

Code: [Select]
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 :|

Code: [Select]
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.

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Switch statement
« Reply #12 on: November 12, 2018, 10:25:39 PM »
I rather think that fallthrough is bad because it's so long to type :P

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Re: Switch statement
« Reply #13 on: November 13, 2018, 09:00:47 AM »
If you put a switch inside a while/for loop, continue currently means: jump to the next loop