does this switch statement smell bad? [closed] - c#

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
Switch(some case) {
case 1:
// compute something ...
return something;
break;
case 2:
// compute something ...
return something;
break;
/* some more cases ... */
case X:
// compute something ...
return something;
break;
default:
// do something
return something;
break;
}
In my opinion:
Assuming this switch statement is justifiable, the return and break just doesnt look right or feel right.
The break is obviously redundant, but is omission poor style (or is this poor style to begin with?) ?
I personally dont do this, but there is some of this in the codebase at work. And no, im not going to be self-righteous and correct the codebase.

No, omission is not poor style - inclusion is poor style. Those are unreachable statements. Get rid of them.
I like the fact that the cases return directly instead of setting a local variable and then returning just at the bottom - it means that it's incredibly clear when you're reading the code that it does just need to return, and that's all.
Side-note in terms of switching in the first place:
As for whether using a switch statement is the right thing to do here, it really depends on other things. Would it make sense to use a polymorphic type instead? If you're in Java, could you use a smart enum? (You can mimic these in C#, but there isn't as much support.)
I'd say this should at least prompt considering different designs - but it may well be the simplest way to do what you want.

The C# Compiler gives a warning if you do this saying that the break is unreachable code. So in my book it is bad form to have both return and break.

In my opinion, I would omit the 'break' keyword. I personally think it helps remind people that 'Execution has ended! Nothing more to see here!'.

I would make a small change:
switch(some case) {
case 1:
// compute something ...
break;
case 2:
// compute something ...
break;
/* some more cases ... */
case X:
// compute something ...
break;
default:
// do something
break;
}
return something;

I'm not sure how literal that code is intended to be so some of these observations may not be applicable...
"case 1"
If you're truly hard-coding numers like this I think it is poor style and you should look into using an enumeration.
If you are simply returning something and there is no additional logic in a subset of the cases, you might consider putting the "somethings" in an array or dictionary and simply addressing them by their index rather than using a switch statement...
return somethings[index]

Code smell implies a design problem. This is just an issue of formatting. I think most people would agree that a version with breaks omitted is superior.

The break is redundant.
Some rule of thumb, It is always good to exit a function in one place only, But since this rule was made Try-Catch was invented (oop goto).
If you keep the same style all over your application, I guess you can live with the return in the switch.

The code smell here is the hard coded values in the case statements.
As for the returns it is more a question of taste and good judgement. Sure if your case spans mutiple pages it is easier to read if the return is in the case, but then the problem is the big switch to begin with.
Personnaly I prefer the single return option because if ever you need to add some more processing then it is cheaper to refactor than visiting all the cases. Also, if given to someone else to refactor they will not have the temptation to copy paste the code in every case, least I would hope so ... if they do they better hope I am not the one doing their code review (for the copy paste obviously).

Switch statements are themselves a code smell.
Along the lines of what l99057j said, if all you're doing is mapping inputs to constant values, this is a place for an appropriate lookup structure, such as an array/list for sequential inputs or a dictionary/map for a sparse one, not a switch statement. If you're calculating something, then the value would be a delegate that you call with the input.

Others have commented on other aspects. As for the breaks that are redundant after the returns: I would KEEP them, along the same reasoning as { } around a single-statement if body: it should be second nature for every programmer to put those braks there. Better have 100's of such redundant breaks than one unintentionally missing.

Related

Fall from one case to another using goto

I have read multiple articles saying using goto is a massive no no in programming. But some specifically indicate that it's the abuse of goto that is wrong and that in some cases, like switch cases, it's the intended use.
So my question to you is, for future reference, which is best practice/more efficient.
this:
switch (a)
{
case 1:
//Something specific for case 1
break;
case 2:
//Something specific to default and case 2
break;
default:
//Something specific for default
goto case 2;
}
or this:
switch (a)
{
case 1:
//Something specific for case 1
break;
case 2:
//Something specific to default and case 2
thatFunction();
break;
default:
//Something specific for default
thatFunction();
break;
}
void thatFunction() { /*Case 2 stuff*/ }
EDIT: These two switch statements are examples, the actual code contains many more cases.
Everyone at my workplace has either never used goto or say they've only heard to never ever use it. So I came here for a definitive answer. I'm looking for an answer and an explanation or links to one.
Thanks,
You always need to understand the reasoning behind any "no-no" (or "yes-yes"). That way you can understand where it makes sense to apply the rule, and where it doesn't.
The big fight against goto goes all the way back to programming without true procedures and functions, or even something as simple as a loop. goto allowed you to jump from anywhere to anywhere else, and it was extremely hard to think about what it actually means. "Don't use goto" was part of the movement to structured code, as opposed to lots of jumps all the way around the code; using things like for (int i = 10; i > 0; i--) { ... } for iteration, rather than if (i-- > 0) goto startLoop;.
In a switch, goto is constrained - it can only do one thing, execute a branch of the switch statement. In fact, in C#, even outside of a switch statement, goto is very constrained and safe, and rarely has any of the implications that were assumed when the "Goto is evil" movement started. That doesn't mean you should start replacing all your loops with gotos, of course :)
Now, if things are getting this complicated, it might be that a switch isn't a good solution for your problem in the first place. Perhaps you can use a different structure to do what you're trying to do - there's many ways to do polymorphism and/or code reuse in C#, and one of those might be a better approach that will allow you to use clearer code to do what you're trying to do. But we can't really help you with that :)
The answer is that logic going in circles is best kept to religion and politics. Your default is really case 2, which means that case 2 is really just default. While it's possible that there's some execution in case 2 that doesn't occur in default, it's extremely rare that you'd ever need to do anything other than an if condition in your default case. Further, in troubleshooting the result of your switch evaluation cannot be immediately determined if you loop backward up the case chain. Imagine your stack trace, too.
There are times to use goto, but these are often in exceptional cases (see what I did there) where you need to immediately execute an action (such as logging something going wrong on another thread) before breaking a run condition or infinite loop. The general rule with goto is the same as with preprocessor commands. If there's another way you can do the same effective thing, you should use the other way for logical continuity and maintainability.

Why not GOTO Statement? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I am doing Masters in Software Engineering. From College to University i heard from my teachers and instructors that never use GOTO statement in Programming Language.According to
Software Engineering By D. Sundar
USE of goto statements makes a program unstructured and makes it very
difficult to understand.
and i also read the same in book by MICROSOFT on its first page that never use GOTO Statmement in Programming.
It always arises question in my mind that if we are instructed that never use GOTO Statement then why it is the part of many common programming languages ?
At least for some programming languages (none of which I'm the designer of, obviously) like C and C++, I imagine it's there because it
Closely models what the hardware really can do, which is kind of the goal in these languages.
Is sometimes actually useful and better than more "structured" approaches.
The most common example of when goto is often considered good is when doing nested error/resource management in C. See for instance the Linux kernel, a fairly large and successful C project which uses goto for this purpose.
You want to read the seminal "Go to statement considered harmful" by Edsger W. Dijkstra (1968!)
There is no goto statement in java. The Java keyword list specifies the goto keyword, but it is marked as "not used".
You instructed not to use goto because they want to teach you how to write code.
but sometimes goto can be useful.
when you want to break at once from a multi-level loop. you can add an exit condition to each step. and you can use goto endloop
look at this example: (psaudo code)
while(cond1){
while(cond2){
while(cond3){
if(want to break){
goto endloop
}
do something
if(want to break2){
goto endloop
}
}
do something
}
do something
}
endloop:
do something else
without the goto it may look like this:
while(cond1 && exitloopflag){
while(cond2 && exitloopflag){
while(cond3 && exitloopflag){
if(want to break){
exitloopflag = true;
break;
}
do something
if(want to break2){
exitloopflag = true;
break;
}
}
if(exitloopflag)
break;
do something
}
if(exitloopflag)
break;
do something
}
do something else
so we can argue which code readability is better...
The presence of goto in any modern programming language is largely vestigial, sort of like the human appendix. Its functionality has been replaced with conditional and looping control structures (if-then-else, for/while/loops, switch/case statements, etc.). It hangs around in languages like C and C++ because there are edge cases where it's still quite useful, such as breaking out of a deeply nested loop:
for (...)
{
for (...)
{
for(...)
{
...
// hit a fatal error, need to break out to outermost scope
goto whoopsiedoodle;
}
}
}
whoopsiedoodle:
...
However, its use is discouraged for a number of very good reasons: since it can branch either direction in a function, it can destroy the ability to debug code by simple inspection. For example, given the following snippet:
i = 1;
label: printf("i = %d\n", i);
What value gets printed for i? How many times will that print statement be executed? Until you account for every instance of goto label;, you can't know. Now, imagine the code is structured something like the following:
i = 0;
goto label;
foo: ...
...
i = 1;
label: printf("i = %d\n", i);
...
goto foo;
...
Now, imagine several dozen (or even several hundred) lines of code for each ... in the snippet above. Also imagine the presence of 10 or 11 other labels scattered throughout, with associated goto statements scattered largely at random. This is modeled after some real-world code I encountered early in my career. The only way to debug code like this is to trace the execution, line by line, accounting for every goto along the way. This code was badly written to begin with (a monolithic, 5000-line main function, literally hundreds of separate variables, some declared at file scope, some local to main, and other atrocities), but the use of goto was a force amplifier that turned merely bad code into an unmaintainable sludge. This code defined "brittle"; we literally could not change a single line of it without breaking something else.
Excessive use of goto can also hinder the compiler's ability to optimize code. Modern compilers are quite smart, and can take advantage of structured programming techniques to do effective branch prediction or unroll loops for real performance gains. Code like the above is almost impossible for the compiler to optimize. That real world code that the above snippet is modeled on? We tried to compile it with optimization flags turned on (gcc -O1). The compiler ate all available RAM, then it ate all available swap, causing a kernel panic.
We told the customer they would either need to buy faster hardware, or allow us to rewrite the entire thing from the keel up. They wound up buying faster hardware.
goto can be used effectively, as long as you obey the following rules:
Branch forward only.
Never branch into the body of a control structure (i.e., don't bypass the if, for, while, or switch condition).
Avoid branching over large sections of code.
Id like to give an explanation, why you should use GOTO very carefully.
I do not say GOTO is a bad statement at all, that is one of the reasons, why it is still implemented in C++ (and due to compatibility reasons to C), in JAVA its only reserved as a keyowrd.
I can show you examples where GOTO is the best solution (in my point of view)
But you should prevent using it due to the following reason:
(Taken, translated and modified by me, from the Book Ohne C Zu C++)
Imagine you play a game like Settlers of Catan, wherever you go, anyone has its own
rules.
That is ok, you just need to learn the rules and then you can play with them.
But what is if they will not teach u there rules, and just use it? you will loose the fun in gaming with
them very fast.
A goto statement is like a new Settler of Catan rule.
Programming is hard enough to understand when you can reliably assume that you start at >the top, execute 1 line at a time, going down, one line at a time.
Using a goto statement throws that assumption out the window, and all of the sudden, the "game! is uncertain. It's a new and uncertain rule.
In some languages, it is used for exception handling (e.g. VBA)
Java has goto as a keyword but it is doing nothing. I belivie they did this, that you can't name anything goto
However, in some cases goto can be useful!
goto is explicitly not allowed in Java. It is there in other languages because it is easy to implement as it is a simple instruction in machine code, not because it is a good idea.
BTW You can do something like a goto in Java. See if you can easily work out what this simple example does, and if you can't you are answering your own question. If it's obvious to you what this does and how it works, you have to consider than many would find this confusing.
FOUND: {
for(String s: list)
if(s.contains(like))
break FOUND;
System.out.println(like + " not found");
}
Goto statements model machine code; there are very limited flow-control constructs in machine code, and there is no way to write a significant machine code program without the equivalent of a goto.
The original high-level languages, such as COBOL and FORTRAN, had Gotos because that's how people knew to control their flow from doing machine code on their machines. The C language was also created with one, though years later, partially because that language was specifically created to be easy to compile to efficient machine code -- some of the C language constructs, such as the increment/decrement operators, are there because the machine for which C was originally created had those sub-operations in its machine code. It can be said that C is not a high-level language, it is a structured assembler (and there's nothing wrong with that, it was ahead of its time, and still highly useful).
What Dijkstra and others figured out, though, is that (1) it isn't necessary to have a goto if you have sufficient higher-level constructs for flow control, and (2) it is horribly error-prone. I remember reading that there were analyses of code that found that a goto statement was 9 times more likely to be in error than any other kind of statement.
It is ironic because it is not the least difficult to understand conceptually what the statement is doing; it's just that the uses programmers make of it too often turn out to make the program overall harder to understand.
Goto is permitted when we're jumping
out of a scope,
just next behind the scope close.
All other cases are invalid (jumping into a cycle, jumping into the middle of an if-block, jumping into another function, OMG, happy Halloween).
As there are several way to break a scope, like break, break label, return etc, there is no situation where pure goto must be used (except some early languages which does not support some of above, usually break label).
Other words, goto has not disappeared (it's impossible to write a program without changing the order of execution), we just make distinctions by using different keywords for different types of execution path. Goto now has special cases, which have own keywords. It also makes code easier to understand.

Code compiles and executes even when surrounded only by Braces [duplicate]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
I mean other than using it when required for functions, classes, if, while, switch, try-catch.
I didn't know that it could be done like this until I saw this SO question.
In the above link, Eli mentioned that "They use it to fold up their code in logical sections that don't fall into a function, class, loop, etc. that would usually be folded up."
What other uses are there besides those mentioned?
Is it a good idea to use curly braces to limit the scope of your variables and expand the scope only if required (working on a "need-to-access" basis)? Or is it actually silly?
How about using scopes just so that you can use the same variable names in different scopes but in the same bigger scope? Or is it a better practise to reuse the same variable (if you want to use the same variable name) and save on deallocating and allocating (I think some compilers can optimise on this?)? Or is it better to use different variable names altogether?
I do if I am using a resource which I want to free at a specific time eg:
void myfunction()
{
{
// Open serial port
SerialPort port("COM1", 9600);
port.doTransfer(data);
} // Serial port gets closed here.
for(int i = 0; i < data.size(); i++)
doProcessData(data[i]);
etc...
}
I would not use curly braces for that purpose for a couple reasons.
If your particular function is big enough that you need to do various scoping tricks, perhaps break the function into smaller sub-functions.
Introducing braces for scoping to reuse variable names is only going to lead to confusion and trouble in code.
Just my 2 cents, but I have seen a lot of these types of things in other best practice materials.
C++:
Sometimes you need to introduce an extra brace level of scope to reuse variable names when it makes sense to do so:
switch (x) {
case 0:
int i = 0;
foo(i);
break;
case 1:
int i = 1;
bar(i);
break;
}
The code above doesn't compile. You need to make it:
switch (x) {
case 0:
{
int i = 0;
foo(i);
}
break;
case 1:
{
int i = 1;
bar(i);
}
break;
}
The most common "non-standard" use of scoping that I use regularly is to utilize a scoped mutex.
void MyClass::Somefun()
{
//do some stuff
{
// example imlementation that has a mutex passed into a lock object:
scopedMutex lockObject(m_mutex);
// protected code here
} // mutex is unlocked here
// more code here
}
This has many benefits, but the most important is that the lock will always be cleaned up, even if an exception is thrown in the protected code.
The most common use, as others have said, is to ensure that destructors run when you want them to. It's also handy for making platform-specific code a little clearer:
#if defined( UNIX )
if( some unix-specific condition )
#endif
{
// This code should always run on Windows but
// only if the above condition holds on unix
}
Code built for Windows doesn't see the if, only the braces. This is much clearer than:
#if defined( UNIX )
if( some unix-specific condition ) {
#endif
// This code should always run on Windows but
// only if the above condition holds on unix
#if defined( UNIX )
}
#endif
It can be a boon to code generators. Suppose you have an Embedded SQL (ESQL) compiler; it might want to convert an SQL statement into a block of code that needs local variables. By using a block, it can reuse fixed variable names over and over, rather than having to create all the variables with separate names. Granted, that's not too hard, but it is harder than necessary.
As others have said, this is fairly common in C++ due to the all-powerful RAII (resource acquisition is initialization) idiom/pattern.
For Java programmers (and maybe C#, I don't know) this will be a foreign concept because heap-based objects and GC kills RAII. IMHO, being able to put objects on the stack is the greatest single advantage of C++ over Java and makes well-written C++ code MUCH cleaner than well-written Java code.
I only use it when I need to release something by the means of RAII and even then only when it should be released as early as I possibly can (releasing a lock for example).
Programming in Java I have quite often wanted to limit scope within a method, but it never occurred to me to use a label. Since I uppercase my labels when using them as the target of a break, using a mixed case labeled block like you have suggested is just what I have wanted on these occasions.
Often the code blocks are too short to break out into a small method, and often the code in a framework method (like startup(), or shutdown()) and it's actually better to keep the code together in one method.
Personally I hate the plain floating/dangling braces (though that's because we are a strict banner style indent shop), and I hate the comment marker:
// yuk!
some code
{
scoped code
}
more code
// also yuk!
some code
/* do xyz */ {
scoped code
}
some more code
// this I like
some code
DoXyz: {
scoped code
}
some more code
We considered using "if(true) {" because the Java spec specifically says these will be optimized away in compilation (as will the entire content of an if(false) - it's a debugging feature), but I hated that in the few places I tried it.
So I think your idea is a good one, not at all silly. I always thought I was the only one who wanted to do this.
Yes, I use this technique because of RAII. I also use this technique in plain C since it brings the variables closer together. Of course, I should be thinking about breaking up the functions even more.
One thing I do that is probably stylistically controversial is put the opening curly brace on the line of the declaration or put a comment right on it. I want to decrease the amount of wasted vertical space. This is based on the Google C++ Style Guide recommendation..
/// c++ code
/// references to boost::test
BOOST_TEST_CASE( curly_brace )
{
// init
MyClass instance_to_test( "initial", TestCase::STUFF ); {
instance_to_test.permutate(42u);
instance_to_test.rotate_left_face();
instance_to_test.top_gun();
}
{ // test check
const uint8_t kEXP_FAP_BOOST = 240u;
BOOST_CHECK_EQUAL( instance_to_test.get_fap_boost(), kEXP_FAP_BOOST);
}
}
I agree with agartzke. If you feel that you need to segment larger logical code blocks for readability, you should consider refactoring to clean up busy and cluttered members.
It has its place, but I don't think that doing it so that $foo can be one variable here and a different variable there, within the same function or other (logical, rather than lexical) scope is a good idea. Even though the compiler may understand that perfectly, it seems too likely to make life difficult for humans trying to read the code.
The company I'm working at has a static analysis policy to keep local variable declarations near the beginning of a function. Many times, the usage is many lines after the first line of a function so I cannot see the declaration and the first reference at the same time on the screen. What I do to 'circumvent' the policy is to keep the declaration near the reference, but provide additional scope by using curly braces. It increases indentation though, and some may argue that it makes the code uglier.

Does anyone still use [goto] in C# and if so why? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I was wondering whether anyone still uses the "goto" keyword syntax in C# and what possible reasons there are for doing so.
I tend to view any statements that cause the reader to jump around the code as bad practice but wondered whether there were any credible scenarios for using such a syntax?
Goto Keyword Definition
There are some (rare) cases where goto can actually improve readability. In fact, the documentation you linked to lists two examples:
A common use of goto is to transfer control to a specific switch-case label or the default label in a switch statement.
The goto statement is also useful to get out of deeply nested loops.
Here's an example for the latter one:
for (...) {
for (...) {
...
if (something)
goto end_of_loop;
}
}
end_of_loop:
Of course, there are other ways around this problem as well, such as refactoring the code into a function, using a dummy block around it, etc. (see this question for details). As a side note, the Java language designers decided to ban goto completely and introduce a labeled break statement instead.
I remember this part
switch (a)
{
case 3:
b = 7;
// We want to drop through into case 4, but C# doesn't let us
case 4:
c = 3;
break;
default:
b = 2;
c = 4;
break;
}
To something like this
switch (a)
{
case 3:
b = 7;
goto case 4;
case 4:
c = 3;
break;
default:
b = 2;
c = 4;
break;
}
Refer This
I use it extensively in Eduasync to show the kind of code that the compiler generates for you when using async methods in C# 5. You'd see the same thing in iterator blocks.
In "normal" code though, I can't remember the last time I used it...
The compiler uses goto statements in various pieces of generated code, for example in generated iterator block types (generated when using the yield return keyword - I'm pretty sure that the generated XML serialisation types also have a few goto statements in there somewhere too.
See Iterator block implementation details: auto-generated state machines for some more details on why / how the C# compiler handles this.
Other than generated code there isn't a good reason to use a goto statement in normal code - it makes the code harder to understand and as a result more error-prone. On the other hand using goto statements in generated code like this can simplify the generation process and is normally fine because nobody is going to read (or modify) the generated code and there is no chance of mistakes being made because a machine is doing the writing.
See Go-to statement considered harmful for an argument against goto as well as a classic piece of programming history.
I don't remember ever using goto. But maybe it improves the intent of a forever loop that you really never want to exit (no break, but you can still return or throw):
forever: {
// ...
goto forever;
}
Then again, a simple while (true) should suffice...
Also, you could use in a situation where you want the first iteration of a loop to start in the middle of the loop: look here for an example.
goto is great for breaking out of many loops where break would not work well (say upon error conditions), and as Kragen said goto is used by the compiler to generate switch statements and some other things as well.
The processor implements at least one jump instruction and I'm sure lots of statements use those in thier implementation or interpretation.
One of the good things about using a 3rd or 4th generation langauge is that these physical details are abstracted away from us. Whilst we should be mindful of the law of leaky abstraction I think that we should also use our tools as they are intended (sorry). If I were writing code and a goto seemed like a good idea, it would be time to refactor. The purpose of a structured language is to avoid these "jumps" and to create a logical flow in our engineering.
I should avoid the use of break but I can't overlook the performance benefit. However, if I have nested loops that mutually need to break it is time to refactor.
If anybody can propose a use of goto that seems better than refactoring I will gladly withdraw my answer.
I hope I'm not guilty of rushing to the "bike shed" here. Like Kragen says, whats good enough for Dijkstra is good enough for me.
Goto is never better. And continue, break (except in switch/case), (multiple) return, and throw should also be kept to the barest minimum. You never want to escape from the middle of nest loops. You always want the loop control statements have all the loop control. Indenting has information, and all these statement throw that information away. You might as well take out all the indenting.

Why do you need to put break after the last label of a switch statement?

Surely the compiler knows that it's the last label of the switch statement?
Having a break after your switch's final case statement is good defensive programming. If, perhaps in the future, another case statement is added below, it removes the risk of the program's flow falling through from the case above.
It's because in C++ this is what happens:
switch(a)
{
case 1:
// do stuff
case 2:
// do other stuff
}
If a is 1, then - according to C++ rules - both "do stuff" and "do other stuff" would happen. So that C++ programmers coming to C# do not get tripped up (and to make code clearer all 'round), C# requires that you explicitly specify whether you want to break or fall through to a different label.
Now, as for why you need the break on the last block, that's a simple matter of consistency. It also make re factoring easier: if you move the cases around, you don't suddenly end up with errors because of a missing break statement. Also, what happens when you want to add another label, etc, etc.
Consistency. Same reason as being able to have a comma after the last enum definition or the last assignment in an object instantiation statement with braces. And the last case might not always be the last case.
It also makes it so there are fewer special cases.
And if that's the case, then it is easier to learn, write, or read. Although that adds to the consistency thing.
In C# switch statements you must explicitly state to break or goto another case or goto default.
In C and C++, switch statements have fall through labels without a break. Having the user explicitly say what they want to do is important in C# to avoid bugs. A lot of users come to C# from C++ for example.
About the last case statement in particular that you're asking about. I can think of 3 good reasons.
It's important to keep things consistent in any language.
What if you append another case after it later on, what should be done with default?
Why should break be the default? Why not goto? There is ambiguity here.
According to http://msdn.microsoft.com/en-us/library/06tc147t.aspx
You cannot "fall through" any switch section, including the last one.
Fall through can be avoided by any of the following: break, goto, or return.
Actually There is one case when you don't have to put break
Consider this code:
using System;
public class Program
{
public static void DoStuff()
{
}
public static void DoAnotherStuff()
{
}
public static void Main()
{
switch(1)
{
case 1: DoStuff(); break;
default: DoAnotherStuff();
}
}
}
Using C# 4.0 compiler it only gives you a nice CS0162: Unreachable code warning
It appears that since switch has a constant expression the compiler already knows wich path it's going to execute, then just ignores the dafault label.
The cool thing is that if you change switch(1) to switch(2) it no longer compiles because the default label lacks its break.
Edit: From the C# Reference
The requirement in C# is that the end of every switch section, including the final one, is unreachable. Although this requirement usually is met by using a jump statement, the following case also is valid, because the end of the statement list cannot be reached.
case 4:
while (true)
Console.WriteLine("Endless looping. . . .");
That explains why the default does not need a break. In fact any unreacheable label doesn't need a break nor return nor goto
When using a switch, to break is not the only option. You also have the option of going to another case, going to the default case, going to another label, or returning. It is also possible to have multiple cases that have a single implementation body. Since there are up to five options plus the ability to have multiple cases for one implementation, the compiler is not able to simply put in the "correct" answer.
You have to choose what you intend to do. It ensures the compiler does the right thing, makes your code clearer, and makes it more difficult to do dumb-programmer-things, like add another case after the "last one", and forget to put in a break/goto/return.
According to this blog post by Eric Lippert (Case 2), it allows you to be able to arbitrarily re-order your switch sections without accidentally introducing a breaking change:
It [the compiler] requires that every switch section,
including the last one, have an
unreachable end point. The purpose of
this rule, and of the no-fall-through
rule in general, is that we want you
to be able to arbitrarily re-order
your switch sections without
accidentally introducing a breaking
change.
As mentioned, you can use default:, but consider case null too. case null: does need a break;
case null:
iEvaluatedToNothing();
break;
If you want to "waterfall" down you can do something like this;
switch (deliverMail)
{
case null:
case "":
case "Address0":
deliverMail0();
goto case "1";
case "1":
deliverMail1();
break;
}
You can use this with breaks as needed, but one is required on the last evaluation.

Categories