Is switch statement the same as if statement in this specific code? - c#

I am trying to understand whether a specific switch statement is equivalent to this if statement.
if (killstreak == 1) //If killstreak is 1, give one throwing knife and write Mr. Kniferino on screen.
{
attacker.GiveWeapon("throwingknife_mp");
attacker.Call("iprintlnBold", "^2Mr. Kniferino");
attacker.SetPerk("specialty_scavenger", true, false);
}
if (killstreak == 2) //If killstreak is 3, give 10 bullets and write You've received 10 bullets on screen.
{
attacker.Call("setweaponammoclip", "iw5_fnfiveseven_mp_tactical", 8);
attacker.Call("setweaponammostock", "iw5_fnfiveseven_mp_tactical", 0);
attacker.Call("iprintlnBold", "^2You've received 10 ^1bullets");
}
if (killstreak == 3) //If killstreak is 2, give Scavenger and write Scavenger on screen.
{
AfterDelay(10, () =>
attacker.SetPerk("specialty_scavenger", true, true));
attacker.Call("iprintlnBold", "^4Scavenger");
}
So would this if statement be equivalent to this switch statement?
switch (killstreak)
{
case 1:
attacker.GiveWeapon("throwingknife_mp");
attacker.Call("iprintlnBold", "^2Mr. Kniferino");
attacker.SetPerk("specialty_scavenger", true, false);
break;
case 2:
attacker.Call("setweaponammoclip", "iw5_fnfiveseven_mp_tactical", 8);
attacker.Call("setweaponammostock", "iw5_fnfiveseven_mp_tactical", 0);
attacker.Call("iprintlnBold", "^2You've received 10 ^1bullets");
break;
case 3:
AfterDelay(10, () =>
attacker.SetPerk("specialty_scavenger", true, true));
attacker.Call("iprintlnBold", "^4Scavenger");
break;
}
If something isn't clear, I'll happily explain again.

Almost, but not quite. The outcome in your case will be the same (so you could say that they are different ways of achieving the same logic). The difference is that your if statement tests would all be executed, while the switch would only evaluate once, than branch to the appropriate case.
You could add else statements to terminate early but still there is a fundamental difference between switch statements and if/else chains. The latter give you more flexibility, while the switch could technically, be optimized by the compiler into a branch table, and the condition (if it's an expression) will only be evaluated once.
This would be more like a switch statement but still, not exactly the same:
if (killstreak == 1)
{
/* case 1 */
}
else if (killstreak == 2) // only tested if killstreak != 1
{
/* case 2 */
}
else if (killstreak == 3) // only tested if killstreak != 1 and != 2
{
/* case 3 */
}
But as I said, this is still not entirely the same. A switch statement may be translated by the compiler into equivalent code to the if/else chain above, but it could be translated into a lookup table too, something more like this:
BranchTable = [CASE1_ADDR, CASE2_ADDR, CASE3_ADDR]
goto BranchTable[killstreak]
CASE1_ADDR:
/* code for test 1*/
goto AFTER_SWITCH_ADDR;
CASE2_ADDR:
/* code for test 2*/
goto AFTER_SWITCH_ADDR;
CASE3_ADDR:
/* code for test 3*/
AFTER_SWITCH_ADDR:
/* code following swtich statement */

Functionally, yes, it's the same, given that 1 can never equal 2 or 3. killstreak is always going to be equal to one of those and not the others.
But logically, the construction you've made here differs in an important way. switch statements in C# are more identical to if/else-if/else (with default) than they are to if/if/if. break prevents the control flow from passing any further upon the first time you encounter a case that evaluates to true, whereas every single one of your if statements will always be evaluated.
For example, if you accidentally hit the wrong key when constructing your second conditional:
if (killstreak == 1)
{
FunctionOne();
}
// should have been 2
if (killstreak == 1)
{
FunctionTwo();
}
both FunctionOne() and FunctionTwo() would execute, because those two conditionals are logically independent of one another. The result of one has no bearing on whether the next is executed.
(Edit: it's been pointed out that there's not really a way at all to have two identical cases in switch statements. They require either literals or constants, and will fail to compile if the same value is used for multiple cases. I've removed that portion.)
An easy way to deal with this in terms of if blocks where you only ever want one portion of code to execute is using else if:
if (killstreak == 1)
{
FunctionOne();
}
else if (killstreak == 1)
{
FunctionTwo();
}
This would execute identically to the example switch statement above - only FunctionOne() would ever be executed. Your typo no longer causes two separate killstreak actions to execute each time the user gets a single kill.
Edit: Namfuak points out another possibility - if somehow killstreak was incremented within FunctionOne(), when execution came to the second if block below, FunctionTwo() would also execute.
// killstreak is 1
if (killstreak == 1)
{
// will execute
FunctionOne(); // increments killstreak
}
// killstreak is 2
if (killstreak == 2)
{
// will also execute
FunctionTwo();
}

Related

Nested if-conditions vs multiple separated if-conditions with return statement in each one

What is the most professional code-style in the below two functions ?
And what if the function become more complex & larger such as to have 20 checks ?
Note: i need to do some stuff after each check, so i can't concatenate all in one if-statement like:
if (vehicle.isBus) && (vehicle.numberOfWheels == 6) && (vehicle.motorVersion == 2019)
//first alternative
public bool validate(Vehicle vehicle)
{
if(vehicle.isBus)
{
//do some stuff here related to vehicle.isBus
if (vehicle.numberOfWheels == 6)
{
//do some stuff here related to vehicle.numberOfWheels
if (vehicle.motorVersion == 2019)
{
//do some stuff here related to vehicle.motorVersion
return true;
}
}
}
return false;
}
//second alternative
public bool validate(Vehicle vehicle)
{
if (!vehicle.isBus)
{
return false;
}
//do some stuff here related to vehicle.isBus
if (vehicle.numberOfWheels != 6)
{
return false;
}
//do some stuff here related to vehicle.numberOfWheels
if (vehicle.motorVersion != 2019)
{
return false;
}
//do some stuff here related to vehicle.motorVersion
return true;
}
One golden rule I follow is to Avoid Nesting as much as I can.
Use the one that makes the code more readable and understandable. For just two conditions, the first way is more logical and readable. It might not be the case anymore with 5 or 6 conditions linked with &&, || and !.
So when the number of checks are 5+ then you should prefer second alternative.
Note : Multiple ifs without each calling return implies that 2 or more ifs could be true.
The second example should require less cognitive overhead while reading the code.
In the first example, you need to keep a mental "stack" of the program state. In the second example, you just need to keep a list of things that you already know to be true.
The second example is also less likely to be confounded by a misplaced brace; in fact it doesn't require any braces at all in this example.

Forcing SWITCH to process all statements or break if case match [StateMachine]

Let's say I need to go through bunch of statements and process each case, results of which will be "incrementation" of IntVar. So like:
int result = 1;
if (condition1)
{
result = result + 2;
}
if (condition2)
{
result++;
}
if (condition3)
{
result++;
}
//things get hairy
if (result != 5 && condition4)
{
result++;
}
if (result != 5 && condition5)
{
result++;
}
// do a thing based on a result value
I' love to use while{} here but I can't because result can be less than 5 when all cases processed. What i had in mind is putting all the checks into SWITCH and make continue to process them until the end (and then continue code normally) UNLESS result hits "5" middle way, then just go straight to result process.
Is it possible to force default SWITCH to do so without writing custom one and/or overcomplicating things too much?

While statement with multiple conditions

I have the following while statement -
while ((!testString.Contains("hello")) && (NewCount != OldCount) && (attemptCount < 100))
{
//do stuff (steps out too early)
}
This is stepping out of the statement even though all the conditions have not been met.
I have tried to reduce it like -
while (!testString.Contains("hello"))
{
// this works and steps out when it should
}
And this steps out when hello is present for example. I also tried changing this to an OR statement which reversed the problem to never stepping out the statement.
Addint the && (NewCount != OldCount) && (attemptCount < 100)) conditions is causing this behaviour how can I resolve this?
This is stepping out of the statement even though all the conditions
have not been met.
To achieve that you need to specify logical OR (||).
For example:
while ((!testString.Contains("hello")) || (NewCount != OldCount) || (attemptCount < 100))
{
//while at least one those conditions is true, loop will work
}
Which means that inside loop you need to introduce security checks, where required, for conditions which are not more true, while loop is still executing.
As an addition to Tigran´s answer. Often (in order to avoid mess with the complex condition) it could be useful to push the condition into the loop:
while (true) { // loop forever unless:
if (testString.Contains("hello")) // ...test string contains "hello"
break;
if (NewCount == OldCount) // ...counts are equal
break;
if (attemptCount >= 100) // ... too many attempts
break;
// ...it's easy to add conditions (as well as comment them out) when you have them
// Loop body
}

If Condition inside switch case [duplicate]

This question already has answers here:
Control cannot fall through from one case label
(8 answers)
Closed 9 years ago.
I am trying to convert an if statement to switch cases (for readability)
1) I've read switch statements are aweful in general - Is that true?
https://stackoverflow.com/questions/6097513/switch-statement-inside-a-switch-statement-c
2) The statement goes like this:
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
case Display.NonExpense:
if (expected.EXPENSE == true)
break;
case Display.All:
//Code
break;
}
Error is:
Control cannot fall through from one case label ('case 1:') to another
This is the original if statement:
if ((Show == Display.All) || (expected.EXPENSE == true && Show == Display.Expense) || (expected.EXPENSE == false && Show == Display.NonExpense))
{
//Code
}
First off, I notice that you forgot to ask a question in your second point. So I'm going to ask some questions for you addressing your second point:
What is the meaning of the "can't fall through" error?
Unlike C and C++, C# does not allow accidental fall-through from one switch section to another. Every switch section must have an "unreachable end point"; it should end with a break, goto, return, throw or (rarely) infinite loop.
This prevents the common bug of forgetting to put in the break and "falling through" accidentally.
You've written your code as though fall-through is legal; my guess is that you're a C programmer.
How can I force fall-through in C#?
Like this:
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
else
goto case Display.All;
case Display.NonExpense:
if (expected.EXPENSE == true)
break;
else
goto case Display.All;
case Display.All:
//Code
break;
}
Now the reachability analyzer can determine that no matter which branch of the "if" is taken, the switch section endpoint is unreachable.
Is this good style?
No. Your original code was a lot more readable.
I've read switch statements are aweful in general - Is that true?
Opinions vary. Switch statements are very useful when there is a small number of very "crisp" alternatives whose behaviours do not interact in complex ways. Some people will tell you that switched logic should instead be handled by virtual methods or visitor patterns, but that can be abused as well.
Should I use a switch in this particular case?
I wouldn't.
How would you improve my code?
if ((Show == Display.All) ||
(expected.EXPENSE == true && Show == Display.Expense) ||
(expected.EXPENSE == false && Show == Display.NonExpense))
{
//Code
}
First off, don't name things IN ALL CAPS in C#.
Second, don't compare Booleans to true and false. They're already Booleans! If you want to know the truth of statement X you would not say in English "is it true that X is true?" You would say "Is X true?"
I would likely write:
if (Show == Display.All ||
Show == Display.Expense && expected.Expense ||
Show == Display.NonExpense && !expected.Expense)
{
//Code
}
Or, even better, I would abstract the test away into a method of its own:
if (canDisplayExpenses())
{
//Code
}
Or abstract the whole thing away:
DisplayExpenses();
The compiler will not understand what you mean here.
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
// missing break here
case Display.NonExpense:
The compiler will not connect the dots and understand that the break; statement inside your if statement is linked to the switch statement. Instead it will try to link it to a loop, since break; statements on their own can only be used with loops, to break out of it.
That means that your case block is missing its break statement to complete it, and thus the compiler complains.
Instead of trying to wring the necessary code out of a switch statement, I would instead break up your original if statement.
This is yours:
if ((Show == Display.All) || (expected.EXPENSE == true && Show == Display.Expense) || (expected.EXPENSE == false && Show == Display.NonExpense))
{
//Code
}
This is how I would write it:
bool doDisplayExpected =
(Show == Display.All)
|| (Show == Display.Expense && expected.EXPENSE)
|| (Show == Display.NonExpense && !expected.EXPENSE);
if (doDisplayExpected)
{
// code
}
You don't have to pack everything on one line.
Also, I would try to name properties so that they're easier to read, I would rename the EXPENSE property to IsExpense so that the above code would read like this:
bool doDisplayExpected =
(Show == Display.All)
|| (Show == Display.Expense && expected.IsExpense)
|| (Show == Display.NonExpense && !expected.IsExpense);
if (doDisplayExpected)
{
// code
}
Then, ideally, I would refactor out the sub-expressions to methods:
bool doDisplayExpected =
ShowAll()
|| ShowExpense(expected)
|| ShowNonExpense(expected);
if (doDisplayExpected)
{
// code
}
public bool ShowAll()
{
return Show == Display.All;
}
public bool ShowExpense(Expected expected)
{
return Show == Display.Expense && expected.EXPENSE;
}
public bool ShowNonExpense(Expected expected)
{
return Show == Display.NonExpense && !expected.EXPENSE;
}
Then you can put the expression back into the if-statement:
if (ShowAll() || ShowExpense(expected) || ShowNonExpense(expected))
{
// code
}
This should be easier to read, and change later on.
Use if statements and extract complex conditions into methods, e.g
if (ShowAll() || ShowExpense())
{
}
Remember about OOP and polymorphism every time you write such 'switch', adding another
case to that code will be a nightmare
see this and similar (C++) instructions about converting switches
P.S if you are interested in making your code clean and readable, consider reading Smalltalk Best Practice Patterns by Kent Beck and/or Clean Code by Uncle Bob
I really enjoyed both of them, highly recommend.
If you want readability, just throw away your syntax trash:
if (Show == Display.All || expected.EXPENSE && Show == Display.Expense || !expected.EXPENSE && Show == Display.NonExpense)
{
//Code
}
Provide the else part for each of them so it will not throw error, however as others say, you actually don't need switch in this case.
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
// do what you want
break;
else
// do what you want
break;
case Display.NonExpense:
if (expected.EXPENSE == true)
// do what you want
break;
else
// do what you want
break;
case Display.All:
//Code
break;
}
The reason why you get this error is that you are not defining break statements.
You defined the break conditionally.
switch (Show)
{
case Display.Expense:
if (expected.EXPENSE != true)
break;
// Note that the break above is in scope of you if statement, and will
// result in a compiler error
case Display.NonExpense:
...
}
Either make sure every case statement has its own break or group the case statements as follows.
switch (Show)
{
case Display.Expense:
case Display.All:
// do stuff
// Expense and All have the same behavior
}
Refactor out the if statements so you can express it like so:
if (isDisplayAll() || isExpense(expected) || isNonExpense(expected))
{
// Code
}
The extracted logic:
private bool isDisplayAll()
{
return (Show == Display.All);
}
private bool IsExpense(Expected expected)
{
return expected.EXPENSE && (Show == Display.Expense);
}
private bool IsNonExpense(Expected expected)
{
return !expected.EXPENSE && (Show == Display.NonExpense);
}
Agree with Dennis, you don't want a switch case for this problem.
Although probably less readable, you can also use shorter:
if (Show == Display.All || (expected.EXPENSE == (Show == Display.Expense)))
{
//Code
}

Multiple variables in switch statement in c

How to write following statement in c using switch statement in c
int i = 10;
int j = 20;
if (i == 10 && j == 20)
{
Mymethod();
}
else if (i == 100 && j == 200)
{
Yourmethod();
}
else if (i == 1000 || j == 2000) // OR
{
Anymethod();
}
EDIT:
I have changed the last case from 'and' to 'or' later. So I appologise from people who answered my question before this edit.
This scenario is for example, I just wanted to know that is it possible or not. I have google this and found it is not possible but I trust gurus on stackoverflow more.
Thanks
You're pressing for answers that will unnaturally force this code into a switch - that's not the right approach in C, C++ or C# for the problem you've described. Live with the if statements, as using a switch in this instance leads to less readable code and the possibility that a slip-up will introduce a bug.
There are languages that will evaluate a switch statement syntax similar to a sequence of if statements, but C, C++, and C# aren't among them.
After Jon Skeet's comment that it can be "interesting to try to make it work", I'm going to go against my initial judgment and play along because it's certainly true that one can learn by trying alternatives to see where they work and where they don't work. Hopefully I won't end up muddling things more than I should...
The targets for a switch statement in the languages under consideration need to be constants - they aren't expressions that are evaluated at runtime. However, you can potentially get a behavior similar to what you're looking for if you can map the conditions that you want to have as switch targets to a hash function that will produce a perfect hash the matches up to the conditions. If that can be done, you can call the hash function and switch on the value it produces.
The C# compiler does something similar to this automatically for you when you want to switch on a string value. In C, I've manually done something similar when I want to switch on a string. I place the target strings in a table along with enumerations that are used to identify the strings, and I switch on the enum:
char* cmdString = "copystuff"; // a string with a command identifier,
// maybe obtained from console input
StrLookupValueStruct CmdStringTable[] = {
{ "liststuff", CMD_LIST },
{ "docalcs", CMD_CALC },
{ "copystuff", CMD_COPY },
{ "delete", CMD_DELETE },
{ NULL, CMD_UNKNOWN },
};
int cmdId = strLookupValue( cmdString, CmdStringTable); // transform the string
// into an enum
switch (cmdId) {
case CMD_LIST:
doList();
break;
case CMD_CALC:
doCalc();
break;
case CMD_COPY:
doCopy();
break;
// etc...
}
Instead of having to use a sequence of if statements:
if (strcmp( cmdString, "liststuff") == 0) {
doList();
}
else if (strcmp( cmdString, "docalcs") == 0) {
doCalc();
}
else if (strcmp( cmdString, "copystuff") == 0) {
doCopy();
}
// etc....
As an aside, for the string to function mapping here I personally find the table lookup/switch statement combination to be a bit more readable, but I imagine there are people who might prefer the more direct approach of the if sequence.
The set of expressions you have in your question don't look particularly simple to transform into a hash - your hash function would almost certainly end up being a sequence of if statements - you would have basically just moved the construct somewhere else. Jon Skeet's original answer was essentially to turn your expressions into a hash, but when the or operation got thrown into the mix of one of the tests, the hash function broke down.
In general you can't. What you are doing already is fine, although you might want to add an else clause at the end to catch unexpected inputs.
In your specific example it seems that j is often twice the value of i. If that is a general rule you could try to take advantage of that by doing something like this instead:
if (i * 2 == j) /* Watch out for overflow here if i could be large! */
{
switch (i)
{
case 10:
// ...
break;
case 100:
// ...
break;
// ...
}
}
(Removed original answer: I'd missed the fact that the condition was an "OR" rather than an "AND". EDIT: Ah, because apparently it wasn't to start with.)
You could still theoretically use something like my original code (combining two 32-bit integers into one 64-bit integer and switching on that), although there would be 2^33 case statements covering the last condition. I doubt that any compiler would actually make it through such code :)
But basically, no: use the if/else structure instead.

Categories

Resources