views:

248

answers:

14

Hi, let's say I have code in C with approximately this structure:

switch (something)
{
case 0:
  return "blah";
  break;

case 1:
case 4:
  return "foo";
  break;

case 2:
case 3:
  return "bar";
  break;

default:
  return "foobar";
  break;
}

Now obviously, the "break"s are not necessary for the code to run correctly, but it sort of looks like bad practice if I don't put them there to me.

What do you think? Is it fine to remove them? Or would you keep them for increased "correctness"?

+1  A: 

Keep the breaks - you're less likely to run into trouble if/when you edit the code later if the breaks are already in place.

Having said that, it's considered by many (including me) to be bad practice to return from the middle of a function. Ideally a function should have one entry point and one exit point.

Paul R
+15  A: 

Remove the break statements. They aren't needed and perhaps some compilers will issue "unreachable code" warnings.

kgiannakakis
looks like we have consensus :)
houbysoft
The same applies with other unconditional control-jumping statements, like `continue` or `goto` - it's idiomatic to use them in place of the `break`.
caf
+1  A: 

I would say remove them and define a default: branch.

DRL
If there's no sensible default then you should not define a default.
Billy ONeal
there is one, and I defined one, I just didn't put it in the question, edited it now.
houbysoft
+5  A: 

Remove them. It's idiomatic to return from case statements, and it's "unreachable code" noise otherwise.

Stephen
+3  A: 

I would remove them. In my book, dead code like that should be considered errors because it makes you do a double-take and ask yourself "How would I ever execute that line?"

Hank Gay
+2  A: 

I'd normally write the code without them. IMO, dead code tends to indicate sloppiness and/or lack of understanding.

Of course, I'd also consider something like:

char const *rets[] = {"blah", "foo", "bar"};

return rets[something];

Edit: even with the edited post, this general idea can work fine:

char const *rets[] = { "blah", "foo", "bar", "bar", "foo"};

if ((unsigned)something < 5)
    return rets[something]
return "foobar";

At some point, especially if the input values are sparse (e.g., 1, 100, 1000 and 10000), you want a sparse array instead. You can implement that as either a tree or a map reasonably well (though, of course, a switch still works in this case as well).

Jerry Coffin
Edited the post to reflect why this solution wouldn't work well.
houbysoft
@your edit: Yes, but it would take more memory, etc. IMHO the switch is the simplest way, which is what I want in such a small function (it does just the switch).
houbysoft
@houbysoft: look carefully before you conclude that it'll take extra memory. With a typical compiler, using "foo" twice (for example) will use two pointers to a single block of data, not replicate the data. You can also expect shorter code. Unless you have a *lot* of repeated values, it will often save memory overall.
Jerry Coffin
@Jerry Coffin: true. I'll still stick to my solution though because the list of values is very long, and a switch just seems nicer.
houbysoft
+1  A: 

Wouldn't it be better to have an array with

arr[0] = "blah"
arr[1] = "foo"
arr[2] = "bar"

and do return arr[something];?

If it's about the practice in general, you should keep the break statements in the switch. In the event that you don't need return statements in the future, it lessens the chance it will fall through to the next case.

Vivin Paliath
Edited the post to reflect why this solution wouldn't work well.
houbysoft
+8  A: 

I would take a different tack entirely. Don't RETURN in the middle of the method/function. Instead, just put the return value in a local variable and send it at the end.

Personally, I find the following to be more readable:

String result = "";

switch (something) {
case 0:
  result = "blah";
  break;
case 1:
  result = "foo";
  break;
}

return result;
Chris Lively
+1 because I would do the same and do not understand why someone would downrate this solution. I dislike having jumpy code.
jdehaan
+1: but ITYM "tack", not "tact" ?
Paul R
The "One Exit" philosophy makes sense in C, where you need to ensure things are cleaned up correctly. Considering in C++ you can be yanked out of the function at any point by an exception, the one exit philosophy isn't really useful in C++.
Billy ONeal
In theory this is a great idea, but it frequently requires extra control blocks that can hamper readability.
mikerobi
yuuuuuuuuuck! code noise! :P
Stephen
As the function pretty much does just that, I personally think returning inside the switch is more readable.
houbysoft
@Paul R: you're right, I did.
Chris Lively
The primary reason why I do things this way, is that in longer functions it is very easy to miss the exit vector when scanning through code. However, when the exit is always at the end then it's easier to quickly grasp what's going on.
Chris Lively
Well, that, and return blocks in the middle of code just remind me of GOTO abuse.
Chris Lively
@Chris : In longer functions, I totally agree - but that usually speaks to bigger problems, so refactor it out. In many cases, it's a trivial function returning on a switch, and it's very clear what is supposed to happen, so don't waste brain power on tracking an extra variable.
Stephen
For simple functions I'd agree entirely with the "one entrance/one exit" policy, but certainly not as a general rule. In more complicated situations, it can lead to solutions that involve lots of redundant checks that can be avoided by simply returning early.
Mac
+3  A: 

Personally I would remove the returns and keep the breaks. I would use the switch statement to assign a value to a variable. Then return that variable after the switch statement.

Though this is an arguable point I've always felt that good design and encapsulation means one way in and one way out. It is much easier to guarantee the logic and you don't accidentally miss cleanup code based on the cyclomatic complexity of your function.

One exception: Returning early is okay if a bad parameter is detected at the beginning of a function--before any resources are acquired.

Amardeep
A: 

I say remove them. If your code is so unreadable that you need to stick breaks in there 'to be on the safe side', you should reconsider your coding style :)

Also I've always prefered not to mix breaks and returns in the switch statement, but rather stick with one of them.

thomask
+1  A: 

For "correctness", single entry, single exit blocks are a good idea. At least they were when I did my computer science degree. So I would probably declare a variable, assign to it in the switch and return once at the end of the function

Steve Sheldon
A: 

Interesting. The consensus from most of these answers seems to be that the redundant break statement is unnecessary clutter. On the other hand, I read the break statement in a switch as the 'closing' of a case. case blocks that don't end in a break tend to jump out at me as potential fall though bugs.

I know that that's not how it is when there's a return instead of a break, but that's how my eyes 'read' the case blocks in a switch, so I personally would prefer that each case be paired with a break. But many compilers do complain about the break after a return being superfluous/unreachable, and apparently I seem to be in the minority anyway.

So get rid of the break following a return.

NB: all of this is ignoring whether violating the single entry/exit rule is a good idea or not. As far as that goes, I have an opinion that unfortunately changes depending on the circumstances...

Michael Burr
A: 

What do you think? Is it fine to remove them? Or would you keep them for increased "correctness"?

It is fine to remove them. Using return is exactly the scenario where break should not be used.

OscarRyz
A: 

I personally tend to lose the breaks. Possibly one source of this habit is from programming window procedures for Windows apps:

LRESULT WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SIZE:
            return sizeHandler (...);
        case WM_DESTORY:
            return destroyHandler (...);
        ...
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

I personally find this approach a lot simpler, succinct and flexible than declaring a return variable set by each handler, then returning it at the end. Given this approach, the breaks are redundant and therefore should go - they serve no useful purpose (syntactically or IMO visually) and only bloat the code.

Mac