Articles

Fall-Through by Default for Switch Statements?

The switch statement has a long history, and most languages support it or something similar.  In my experience, I found it to be very useful — both for conciseness, and also improving performance.  With the recent release of Java 7, you can finally switch over strings.

In Whiley, the syntax for switch statements currently looks like this:

for token in modifiers:
    modifier = null
    switch token.id:
       case "PUBLIC":
       case "public":
          modifier = ACC_PUBLIC
          break
       case "FINAL":
       case "final":
          modifier = ACC_FINAL
          break
       ...
       default:
          throw SyntaxError("invalid modifier",token)

(This excerpt is based on my Java Assembler/Disassembler benchmark)

Now, I’m having something of a dilemma over this syntax: should I support fall-through case statements or not?

As you can see from above, my initial reaction was: yes.  But, I’m starting to think this is a really bad idea and there are a few reasons:

  1. Obviously, fall-through by default is dangerous as its easy to forget the break. I’ve already done this a few times!
  2. Generally, I think fall-through is the exception, not the rule.  That is,  most cases do require the break and, hence, fall-through by default causes additional verbosity.
  3. The overloaded break statement can be annoying when you actually want to break out of a loop.

Now, of course, I’m not the first to think along these lines (see e.g. [1][2][3]) and, in fact, I’m probably being a bit slow on the uptake here!

Several languages (e.g. Go, CoffeeScript, Pascal) do not support fall-through by default. For example, Go supports an explicit fallthrough statement, which might look something like this in Whiley:

for token in modifiers:
    modifier = null
    switch token.id:
       case "PUBLIC":
          fallthrough
       case "public":
          modifier = ACC_PUBLIC
       case "FINAL":
          fallthrough
       case "final":
          modifier = ACC_FINAL
       ...
       default:
          throw SyntaxError("invalid modifier",token)

Go is quite interesting as it provides multi-match case statements as well, which might look like something like this in Whiley:

for token in modifiers:
    modifier = null
    switch token.id:
       case "PUBLIC","public":
          modifier = ACC_PUBLIC
       case "FINAL","final":
          modifier = ACC_FINAL
       ...
       default:
          throw SyntaxError("invalid modifier",token)

I really like this syntax (which I think is originally from Pascal). In Pascal, you can provide ranges as well which certainly makes sense.

So, all things considered, I’m convinced it is a mistake to support fall-through by default in Whiley.  Fortunately, it’s not too late for me to correct this!

The big question then is: do I support explicit fallthrough, multi-match cases or both?

15 comments to Fall-Through by Default for Switch Statements?

  • John Hurst

    Since your language is not C-style curly brace-based, I think its safe to take the no-fall-through route.

    I agree it is more logical and less error-prone. But I think it’s dangerous whenever C-style curly brace languages diverge from what the programmer expects based on previous experience. That’s not going to be the case here.

    Do you support switch on Class as well as String? Java missed that one, sadly.

    JH

  • Hey John,

    Yeah, that was my reasoning originally — stick with what most people will expect. But, I’ve just decided to stuff that … I can’t stand fall-through by default!

    In theory, you will be able to switch on types. However, that is not implemented yet. You can switch on strings already … so it should be easy enough to cover types.

  • Curtis Stanford

    I would say to not allow fall-through but allow multi-match. I think multi-match accounts for most uses of fall-through. The ‘break’ statement in a switch has always rubbed me the wrong way.

  • Daniel

    My initial reaction after reading that you were not so keen on fallthrough by default was to suggest something like multi-match cases. I then scrolled down and saw that you mentioned that too.

    I think you should include both multi-match cases AND explicit fallthrough because just having multi-match cases doesn’t cover the situation where you want a certain case to perform an operation and then fallthrough to another case.

  • Hey Daniel,

    Yeah, I was thinking about that. I have encountered a number of situations where I do something specific and then fall-through to another case. That can still be done by adding an explicit if-statement on the matched value, although I suppose it’s ever-so-slightly less efficient.

  • Daniel

    Yea that’s true, but which one is nicer to write? Also if you did have explicit fallthrough you’d have to come up with some fancy keyword. How would you feel about overriding continue? (Assuming you use continue in the first place)

  • Hey Daniel,

    Ah, I’m ahead of you on this one! Already considered continue, as this makes heaps of sense to me. However, given the conflict with loop-based continue, I still might steer clear of it. I was thinking of “next”, since “fallthrough” is kinda long. Or maybe just “fall”.

    D

  • Daniel

    What makes even more sense to me would be to use next to skip to the next iteration of a loop (what continue is currently used for), and to use continue to fall through to the next case. The only main reason I can see at the moment for not doing this is the legions of C/Java programmers who are already familiar with using the continue keyword in loops.

  • James

    I saw a language a while ago, and of course now I can’t remember what it was, that had default fallthrough for empty case blocks only, i.e:

    case "PUBLIC":
    # falls through to "public"
    case "public":
    modifier = ACC_PUBLIC
    # non-empty block, doesn't fall through to "FINAL"
    case "FINAL":

    I always liked this, but I don’t recall what language used it.

  • Hey Daniel,

    That’s quite a big reason not to, unfortunately!

    D

  • Amir Laher

    I’ve never seen multi-cases before. Nice alternative.

    Here’s a bit of a wide-ball: within a multi-case you could potentially allow a nested switch (on the same variable), which only accepts the values given in the multi-case.

    e.g.

    switch str:
    case "a","b":
    callSomething(str);
    switch str:
    case "a":
    doAThing(str);
    case "b":
    case "c": //<-COMPILER ERROR
    case "c":
    callSomethingElse(str);
    default:
    throw SyntaxError("invalid modifier", str)

    The nice thing about enum switches is that the possible values are pre-defined, and the compiler can even warn you when there’s a case missing. In theory it could do it in the nested switch too.

    I guess it’d be a lot of work for slim gains, but just a thought…

    p.s. +1 for supporting type swtiches.

  • Amir Laher

    (I meant to say that this would provide an alternative to ‘explicit fallthrough’)

  • Eric TF Bat

    I’m given to understand that C# requires either a break or the fall-through equivalent (continue, perhaps?) on every non-empty case section. That would solve the ambiguity problem rather nicely, I think. So something like this:


    switch foo:
    case "BAR":
    wibble
    wobble
    case "BAZ":
    fnord

    … would be a compile-time error, rather than a run-time bug. I like that level of idiot-proofing, personally.

    Personally, I like the Perl 6 idiom, given/when, which is rather more extensible. Off the top of my head, and freely adapting it to what I’ve seen here of your syntax, I think it would work like this:


    given foo:
    when "BAR", "BAZ", "QUUX":
    wibble
    break
    when /^fn[aeiou]+rd$/i: # regular expression match
    wobble
    break
    when .toInteger < 0: # method call on the 'given' value
    glorply
    continue
    default:
    plinge

    I hope the formatting comes through. The lack of preview in this comment form is a mild annoyance.

  • [...] Changed the way cases of a switch statement work.  Now, you can no longer “fall-through by default“. [...]

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>