#2269 Break in Switch?

SlimerDude Wed 23 Apr 2014

If all this talk about Actors and Threads is hurting your head, then here's an easy question to help soothe it!

How about allowing optional break statements in switch expressions? Yes, I know you can not fall through case statements, but there are times (for explicitness and consistency) I want an empty case statement, and that's not allowed.

Consider this trivial example: I have milk delivered on Mon, Wed and Fri, and I want an extra pint on Mon and Fri only. My code may look like:

Weekday day := ...
		
switch (day) {
  case Weekday.mon:
    milk++

  case Weekday.wed:
    // wot to do here?
    // if this case statement is empty, it gets grouped with fri

  case Weekday.fri:
    milk++
}

I need a statement in the wed case to prevent it being grouped with fri and milk being added. I'm not interested in using a default case because I want the code to read explicitly that wed does nothing. (I have a habit, good or bad, of listing all important enums in a switch.)

At the moment I'm using a no-op statement that looks like:

Weekday day := ...
		
switch (day) {
  case Weekday.mon:
    milk++

  case Weekday.wed:
    null?.toStr  // no-op

  case Weekday.fri:
    milk++
}

Which works, is explicit, and is also icky. I would prefer to use break instead:

Weekday day := ...
		
switch (day) {
  case Weekday.mon:
    milk++

  case Weekday.wed:
    break

  case Weekday.fri:
    milk++
}

How about it!?

: )

tomcl Wed 23 Apr 2014

Maybe just a nicer-looking no-op?

pass?

Conceptually what you are doing is NOT breaking - it is - for that case - doing nothing.

brian Wed 23 Apr 2014

I think we had a long discussion about this a while back. I can't remember all the details, but essentially an empty case statement is basically the same as leaving it out altogether. Its only purpose in life is really to help you comment that you explicitly don't want to handle it. Think we just decided that by convention it should be omitted b/c code shouldn't be used for commenting

bfitch Sat 24 May 2014

Just leaving it out doesn't work when there's a default case (for example, to catch unsupported values and throw an exception). A case that you left out on purpose would get handled by the default block and therefore wouldn't "do nothing". There's still a need for a "pass" (or "break") construct to distinguish a do-nothing case from a default case.

Currently, you can use this for "pass", by the way:

|->Void|{}() // do nothing

SlimerDude Wed 28 May 2014

Yep, I came across this exact scenario the other week (using BSON I think). To put it in an example:

switch (day) {
  case Weekday.mon:
    milk += 2

  case Weekday.wed:
    null?.toStr  // do nothing

  case default:
    milk++
}

The no-op for Weekday.wed is required, for if it were to be left out, the default case would be executed.

@bfitch, I prefer null?.toStr over |->Void|{}() as (I believe) the latter creates and executes an anonymous inner class, which involves a small amount of work. Whereas null?.toStr is essentially a simple if statement that always returns false.

Jeremy Criquet Mon 9 Mar 2015

What about:

switch (day) {
  case Weekday.mon:
    milk += 2

  case Weekday.wed:
    day.typeof  // do nothing

  case default:
    milk++
}

I believe that might take less computation?

SlimerDude Mon 9 Mar 2015

Yep, it does!

I still kinda prefer null?.toStr because it's an operation on null which immediately tells you nothing is going to be executed.

Granted, day.typeof also does nothing but (ignoring the // do nothing comment) it can look like a typo or unfinished statement. I think the intent of null?.toStr is clearer.

But yeah, if I was gunning for execution speed, day.typeof is better! :)

Jeremy Criquet Thu 12 Mar 2015

Agreed there and with Fantom, it's probably more often you are looking for readability over nit-picking performance like that (since we're talking about a high level language, here).

Login or Signup to reply.