dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.19k stars 1.57k forks source link

Remove required break keyword from switch/case #2047

Closed sethladd closed 9 years ago

sethladd commented 12 years ago

It is an error to omit the break statement from a non-empty case clause. I suggest we omit the break statement from switch/case as it seems redundant and implies that it isn't required.

DartBot commented 12 years ago

This comment was originally written by jbloc...@gmail.com


I believe this is a no-brainer. Moreover, I believe that it makes little sense to allow multiple statements after a case label. Dart, like C, C++, Java, JavaScript, and C# is a block structured language! You combine multiple statements into a single statements using a pair of braces. Control flow statements (e.g., for, do, while, if, else) control the execution of a single statement (which may be a block). The switch statement is--and has been since the 1970s--an aberration. It is just wrong to bring this aberration with us into the new millenium. It is trivial to fix, as a matter of specification and implementation. Let's do it.

DartBot commented 12 years ago

This comment was originally written by @seaneagan


It would also be more consistent with for, do, while, if, else, to use case(e) instead of case e :.

  switch(x) {     case (1)     case (2) print("0 < x < 3");     case (3) print("x = 3");     case (4)     case (5) print("3 < x < 6");     default print("5 < x");   }

Which would be even nicer if you could combine cases:

  switch(x) {     case (1, 2) print("0 < x < 3");     case (3) print("x = 3");     case (4, 5) print("3 < x < 6");     default print("5 < x");   }

DartBot commented 12 years ago

This comment was originally written by jbloc...@gmail.com


Hi Sean. Funny you should mention it. A syntax I suggested a couple of weeks ago was:

switch(x) {   case(1, 2) {     print("0 < x < 3");   } case (3) {     print("x = 3");   } case(4, 5) {     print("3 < x < 6");   } default {    default print("5 < x");   } }

The sole difference between my proposal and yours is that mine mandates the brackets after each case label (like the do-while statement). I'm not 100% sure how I feel about it, but I like the way it appears similar to a multiway branch implemented as a (nominally nested) if-statement.

rakudrama commented 12 years ago

+1 to not requiring 'break'.

+-0 to removing 'break' entirely. 'break' might still be useful as a way to quickly exit an arm of the switch without incurring the nesting of an if-then-else, somewhat like the clarity of an early exit return.

-1 to requiring parens or braces. It is starting to deviate from 'Dart code should look familiar', and I find it makes the statements harder to read.

When I read a switch statement, I often scan the whole for the case I am interested in ("Did I handle foo?"). Making the case labels look just like other code basically serves to camouflage them. I think Josh's example is sufficiently hard to read that it makes the point :-)

By removing the need to break, many switch statements are more concise. Mandatory braces would squander the gains:

  switch (digit) {     case 0: name = 'zero';     case 1: name = 'one';     case 2: name = 'two';     ...

I would expect the code in an 'arm' between two case labels to be a new scope. Without fallthrough, these scopes are mutually unreachable, and the whole switch is alredy in braces to signal that the variables don't survive the switch.

I'm not so convinced about multiple values.

   case 4, 5:

is not such a huge improvement from

   case 4:    case 5:

when you consider a example with named constants:

  } case (AudioPannerNode.EXPONENTIAL_DISTANCE,           AudioPannerNode.INVERSE_DISTANCE) {     xyzzy();   }

cf

  case AudioPannerNode.EXPONENTIAL_DISTANCE:   case AudioPannerNode.INVERSE_DISTANCE:     xyzzy();

In summary, I think we should make a relatively conservative change. This Dart code:

  case A:   case B:     stuff;     stuff;   case C:

should behave like this C/Java/JavaScript code:

  case A:   case B: {       stuff;       stuff;     }     break;   case C:

DartBot commented 12 years ago

This comment was originally written by @seaneagan


Hi Josh. Independent arrivals at the same conclusion are always a good sign, :-). What's the reason to mandate the brackets ? Also, regarding mapping multiple cases to the same statement, I think something else that can be done is using "patterns" as case expressions, I posted my initial thoughts on this at:

https://groups.google.com/a/dartlang.org/group/misc/browse_thread/thread/e56f45402299f5ac#

DartBot commented 12 years ago

This comment was originally written by @seaneagan


The old default for switch statements was to "continue" to the next branch unless you explicitly "break". This was the incorrect default, which is why Dart mandates "break" in case statements. I'm all for this bug, but it makes "break" the only option, there is no way to get back to the old "continue" semantics, which are useful in some cases especially if cases are allowed to do more than just check for == (see https://groups.google.com/a/dartlang.org/forum/#!topic/misc/5W9FQCKZ9aw).

So why not allow the "continue" keyword in case statements to explicitly get back to the old default? The main concern would be that it means you have to use a labeled continue to refer to outer loops.

DartBot commented 12 years ago

This comment was originally written by 13thLunati...@gmail.com


hi.

I'm from the discussion on the General Dart Discussion:   https://groups.google.com/a/dartlang.org/group/misc/browse_thread/thread/3500924a9d1075ab/5553853479c67716

I think, the "break" is unnecessary in a "switch-case" statement of the Dart. my reason and things was write to the discussion, please read if you has interest.

there is a vote to the theme:

  ++vote: omit the "break"

and, with vote optional to a related talk:

  ++vote: a case syntax change to a blockwise from old C-Style compatible syntax

  ++vote: add a pattern match syntax. (I think users as the Dart targeted are need switch syntax even if add a pattern match syntax to the Dart.)

I'm glad to join the discussion. thanks.

DartBot commented 12 years ago

This comment was originally written by amat...@gmail.com


Comment #­4 @­sra +1

Empty cases are easier to read since every label name starts at the same point:

case "orange", "yellow", "red", "blue":

case "orange": case "yellow": case "red": case "blue":

DartBot commented 12 years ago

This comment was originally written by jjb@google.com


You're assuming that people will actually format "multi-valued case statements" on multiple lines. Many programmers conserve vertical space, so you'll see things like this:

  case "orange": case "yellow": case "red": case "blue":

DartBot commented 12 years ago

This comment was originally written by amatias...@gmail.com


I assume than some people write it on multiple lines and some other write it on one line. I've never seen this and found it harder to read, but is up to the programer.

I mean than multiple cases should not be removed for the ones (like me) who prefer many cases on multiple lines.

sethladd commented 12 years ago

FYI another user tries Dart switch statements: http://japhr.blogspot.com/2012/03/dart-switch.html

From the post:

"I really do not care for that trailing break. It obscures the intent of the code (the direction assignment), decreasing long-term maintainability. I suppose that I could move it to a separate line, but my switch() statement already has two more lines of code than the equivalent if-statement structure.

The only time that I can think to use the switch statement in Dart code is when I have significant, multi-line calculation to perform for each case. Even then it might be better to break those mulii-line statements out into separate functions.

Which begs the question: is there a use-case for Dart's switch()? Unless I can think of one, I may give it a miss in Dart for Hipsters."

sethladd commented 12 years ago

I propose a "baby step" to help deal with this issue.

Can we make a missing break for non-empty case clauses a static warning, or better yet a compile time error? The fact that you don't find out about this missing syntax until runtime is the most unsettling to me.

rakudrama commented 12 years ago

Seth: I don't think the "baby step" is in the right direction. It makes the break necessary, which is the opposite of what I suggested in #­4. Small switch statements look a lot cleaner without the break.

If a static check is implmented, to needs to do some control flow: example - a warning for a missing break following a return, throw, or continue would be irritating.

gbracha commented 12 years ago

Added Duplicate label. Marked as being merged into #2354.

gbracha commented 12 years ago

Issue #3701 has been merged into this issue.

sethladd commented 10 years ago

Added WontFix label. Marked as being merged into #.

hyjfine commented 6 years ago

just something like kotlin when? when (x) { in 1..10 -> print("x is in the range") in validNumbers -> print("x is valid") !in 10..20 -> print("x is outside the range") else -> print("none of the above") }

darkstarx commented 1 year ago

Hi guys! Removing the keyword break is a big mistake! The operator switch is a chain of tests, and you have just broken this chain and haven't left any chance to control the passage of this chain.

With break I can control the process, e.g. like this

final z = 1;
print(z);
switch (z) {
  case 1: print('This is less than two');
  case 2: print('This is less than three');
    break;
  case 3: print(This is three);
    break;
}

It must show

1
This is less than two
This is less than three

Without break the output would be like this

1
This is less than two

Also, since you have left the optional break, it will lead to stupid mistakes of understanding such code. You had to either remove the word break completely, or leave it with the old logic of use.