Switch fallthrough in Dart
Asked Answered
N

5

22

I started learning Dart today, and I've come across something that my google skills are having trouble finding.

How do I have a fall-through in a non-empty case?

My use case is this: I'm writing a sprintf implementation (since dart doesn't have this too), which would work except for this fall-through thing. When parsing the variable type you can, for example, have "%x" versus "%X" where the upper case type tells the formatter that the output is supposed to be uppercase.

The semi-pseudocode looks like:

bool is_upper = false;
switch (getType()) {
    case 'X':
      is_upper = true;
    case 'x':
      return formatHex(is_upper);
}

The other ways I can think of doing this, would one of the following

1:

switch (getType()) {
  case 'X': case 'x':
    return formatHex('X' == getType());
}

2:

var type = getType();
if (type in ['x', 'X']) {
   return formatHex('X' == getType());
}

Now, the second choice almost looks good, but then you have to remember that there are eleven cases, which would mean having eleven if (type in []), which is more typing that I'd like.

So, does dart have some // //$FALL-THROUGH$ that I don't know about?

Thanks.

Northwest answered 23/9, 2012 at 6:13 Comment(0)
M
34

The Dart specification gives a way for a switch case to continue to another switch case using "continue":

switch (x) {
  case 42: print("hello");
           continue world;
  case 37: print("goodbye");
           break;
  world:  // This is a label on the switch case.
  case 87: print("world");
}

It works in the VM, but sadly the dart2js switch implementation doesn't yet support that feature.

Microcline answered 28/9, 2012 at 14:18 Comment(0)
M
8

From the dart language tour, your example of (2) should be correct.

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':     // Empty case falls through.
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeClose();
    break;
}

It would be an error if you tried to do something as follows

var command = 'OPEN';
switch (command) {

  case 'OPEN':
    executeOpen();
    // ERROR: Missing break causes an exception to be thrown!!

  case 'CLOSED':
    executeClose();
    break;
}
Milli answered 23/9, 2012 at 18:46 Comment(1)
It's worth pointing out that missing a break statement no longer causes an Exception (since Dart 3, I believe). That means you should only use break where you need an empty case (as empty cases would normally fallthrough). See dart.dev/language/branches#switch-statementsCenturion
B
6

EDIT: This seems to only have worked due to a bug in the implementation of Dart. See the Dart 1.x language spec, section "17.15 Continue".

The bug is now fixed, as reported in a comment, so this no longer works. Keeping for historical reasons.


Also, a simplification of Lasse's answer is to use a simple continue; instead of continue <label>; as in:

bool is_upper = false;
switch (getType()) {
    case 'X':
      is_upper = true;
      continue;
    case 'x':
      return formatHex(is_upper);
}
Backslide answered 5/10, 2015 at 11:33 Comment(3)
I tried this Aug 2021, version 2.13.4, and got a compiler complaint about continue without a label.Lianaliane
Thanks! Since my original answer is from 2015, the language seems to have moved on.Backslide
When a bug truly is a feature! I hate languages that don't allow allow case fall-through. Even nicer about this is that 'requiring continue' to do it made it explicit, so no one was doing it by accident. *Case fall-through is half the benefit of swtich vs if.Hustle
T
3

You can't have a non-empty case body in Dart that falls through, this will raise an error.

What I tend to do with anything other than very simple switch statements is to refactor all the common code out into functions, so that you don't have this multi-level control flow in the switch itself.

In other words, something like:

switch (getType()) {
    case 'X':
        return formatHex(true);
    case 'x':
        return formatHex(false);
}

There's no reason why you need to have fallthrough. It comes in handy when the actions in a case section can be carried out in toto at the end of another case section, but this method can do that without fallthrough and without making your switch statement complex.

It can also handle more complex cases where there are common actions that aren't included in toto at the end. For example, you may want to do something at the start or in the middle of the case section. Calling common functions handles that more than well enough:

switch (getType()) {
    case 'X':
        doSomethingOnlyForUpperCase();
        doSomethingCommon();
        doSomethingElseOnlyForUpperCase();
        return formatHex(true);
    case 'x':
        doSomethingCommon();
        return formatHex(false);
}

I actually also do this for languages (such as C) that support this sort of non-empty fall-through since I believe it aids in readability and maintainability.

Thaler answered 23/9, 2012 at 6:18 Comment(0)
C
0

Dart in 202207, just empty, instead of continue label

PermissionStatus recordStatus =
              await Permission.requestSinglePermission(
                  PermissionName.Microphone);
 switch (recordStatus) {
      case PermissionStatus.allow:
      case PermissionStatus.always:
      case PermissionStatus.whenInUse:
          return;
      default:
          break;
 }
Circumflex answered 25/7, 2022 at 19:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.