My code accidentally ends up with the following structure. Im not sure that is this ok.
switch (msg.type)
{
case Msg::Type::One:
case Msg::Type::Two:
// do nothing
break;
case Msg::Type::Open:
if (msg.isBad())
break;
else // opened else branch is ok here??
// intended fall through
case Msg::Type::Close:
goodMsg.push_back(msg);
doSomethingOther();
blaBla();
break;
}
It may work, but if you intend to fall through, I would just remove the else altogether, and leave a comment that it is an intentional fall through.
I would suggest against it. When it comes to coding, there's a three-point hierarchy of importance that everyone should follow:
Readability
Functionality
Efficiency
I would argue that what you're trying to do here is an attempt at making this more readable by reducing the amount of code written, but the problem is it actually does the opposite.
Try coming up with another way to accomplish what you're trying to accomplish that is easier for someone who is completely foreign to your code to understand.
One suggestion would be to leave off the empty else, and just have the if statement. While this is arguably still not optimal for readability, it's better than with the else statement, and may actually be tolerable in the workplace.
Let's mark some areas of your code:
switch (msg.type) {
case Msg::Type::One:
case Msg::Type::Two:
// (1)
break;
case Msg::Type::Open:
if (msg.isBad()) {
// (2)
break;
} else {
// (3)
// intended fall through
}
case Msg::Type::Close:
// (4)
goodMsg.push_back(msg);
doSomethingOther();
blaBla();
break;
}
And here's a table showing what code will be run:
(1) (2) (3) (4)
Msg::Type::One ✔︎
Msg::Type::Two ✔︎
Msg::Type::Open && Bad ✔︎
Msg::Type::Open && !Bad ✔︎ ✔︎
Msg::Type::Close ✔︎
That being said, most readers of this code will assume that the fall through condition is a bug. Therefore, I would strongly recommend refactoring this code.
The syntax of an if statement is either:
if (expression) statement
or
if (expression) statement else statement
In your code, the statement associated with the else keyword is the entire switch statement the goodMsg.push_back(msg); (which happens to have a case label associated with it).
I can't tell from your question whether that's what you intended, though your indentation suggests that you meant the switch statement to be independent of the if/else.
If that's what you intended, the else is not useful. Your logic would be more clearly expressed as:
if (condition) break;
case ...
My suggestion: always use curly braces for conditional and loop statements. This lets you avoid having to ask questions like this in the first place:
if (condition) {
statement
}
else {
statement
}
An if / else if / ... / else chain is a special case. Syntactically, it's a nested set of if/else statements, but it's convention to treat it as a linear chain, writing:
if (condition) {
statement
}
else if (condition) {
statement
}
else {
statement
}
rather than:
if (condition) {
statement
}
else {
if (condition) {
statement
}
else {
statement
}
}
Note that I'm using K&R-style brace placement, with each { at the end of a line. Another very common style places both { and } on lines by themselves. Both choices are valid (I obviously have my own preference), as long as you're consistent.
Related
I have the exact same lines of code in the both do something section so I want to merge the two sections into one.
But I don't want to create a separate function for do something.
Is there a way to go to condition A's else when it reaches condition B's else?
if (conditionA)
{
//some code here
if (conditionB)
{
}
else
{
//do something
}
}
else
{
//do something
}
Jumping through code is definitely discouraged, if you really want to minimize the code then the only thing you can do is to rearrange the flow to better suit your needs, eg:
if (conditionA)
{
some code
if (conditionB)
do something else
}
if (!conditionA || !conditionB)
do something
If you (as indicated in the comments) don't want to create a function that you need to pass 6 arguments, then you could use a lambda like this:
const auto do_something = [&] { /* do stuff with captured reference variables */ };
if (conditionA) {
// some code here
if (conditionB) {
// stuff
} else {
do_something();
}
} else {
do_something();
}
if-else is really just syntactic sugar for gotos. You can use an explicit goto here:
if (conditionA)
{
//some code here
if (conditionB)
{
}
else goto do_something;
}
else
{
do_something: /*...*/;
}
This could/should be faster than adding another if check.
Alternatively, you can use an inlinable static function. There should be no performance difference if it does get inlined (and it won't piss off gotos-considered-harmful dogmatists).
(In my opinion, an occasional, clean, downward goto won't harm the readability of your code, but the dogmatism against gotos is strong (as evidenced by downvotes on this answer :D)).
Given that there is no code after //do something, You can use a pattern such as
if (conditionA)
{
//some code here
if (conditionB)
{
//do something else
return;
}
}
//do something
However a clearer pattern would be to encapsulate //do something into a separate function.
To answer what you are asking in the title: Yes, it is possible. There are at least three ways I can think of:
Using goto's (highly discouraged)
Putting "do something" code in a function (perhaps inline for performance) (may result to cleaner code)
Reformatting your if/else statements and merging your conditions as demonstrated in other answers. The rationale is to group the code segments that appear twice (by unifying logical expressions using operators). (I would prefer this way if the code is not that large or if it has high dependencies with other parts)
I would change conditions and rearrange the code a bit.
if (!conditionA || (conditionA && !conditionB))
do_something();
else if (conditionA) {
some_code_here();
if (conditionB)
// Your `if(conditionB)` section goes here.
}
Another possibility (one I think is often preferable) is to combine the conditions into a single variable, then use a case statement for the combinations:
unsigned cond = ConditionA | (ConditionB << 1);
enum { neither, A, B, both};
switch (cond) {
neither: // Both A and B were false;
A: // Only A was true;
B: // Only B was true;
both: // both A and B were true;
}
Then when you want the same code executed for two conditions, you just let normal switch fall-through happen.
You can wrap it up into cthulhu loop and use break:
for(;;) // executed only once
{
if (conditionA)
{
//some code here
if(conditionB)
{
// some more code here
break; // for(;;)
}
}
//do something
break; // for(;;)
}
I think this is more alegant then use for(;;) (VTT answer, which I upwoted)
do
{
if(conditionA )
{
//some code here
if(conditionB)
{
//some code
break;
}
}
// do something
} while(0);
do{...} while(0);
the usage of do{}while(0); in my coding is used because, i do not want to use long if else nested conditional statements. I eventually give an break at the time of failure and move out of the loop, with a assurance that my function would have been traversed at least 1 time.
Now, the problem comes with the code warning tools, I am getting a warning at the usage of do{...}while(0);
the usage of nested if(){} else{} is less readable, high complex. and lets the code to be having dead code.
if i exclude nested if(){} else{} and do{} while(0); , do we left part with some other way to make code readable with understandable logic;
if(status_of_funcA_ok != funcA())
{ //failure}
else if (status_of_funcB_ok != funcB())
{//failure}
else if (status_of_funcC_ok != funcC())
else
{//Great}
do{
if(status_of_funcA_ok != funcA())
break;
if (status_of_funcB_ok != funcB())
break;
if (status_of_funcC_ok != funcC())
break;
}while(0);
Move the complete logic of the do while{0} loop to a function, and replace the break with return. And call the function, instead of the loop.
You will not have to worry about the beauty.
The compiler also doesn't have to complain about the do while{0}.
All the more, by adding a bit of modularity, the program might be a little more readable.
In any case, before doing this, it would be nice to check whether your compiler is in an extremely pedantic mode, and you might want to turn that off. That might take the warning away.
ss.
PS: You don't seem to need a return value for the function, but you could have that to get a clue of which function was successful.
I am using this pattern too, for those who wonder, here's an abstract example:
do // while(0) for break
{
state1 = 0;
if (cond1())
{
if (cond2())
break;
state1 = opA();
}
if (cond3() || state1 && state1->cond4())
break;
...
Triumph(state1, ...);
// often here: return
}
Failure(state1, ...);
I consider this valid in the following circumstances:
you have a long-ish sequence (say, >~half a dozen of conditions)
the conditions are complex, and you use / build up significant state, so you can't
isolate the elements into functions
you are in an exception-unfriendly environment, or your break-ing code path is
not actually an exception
What you can do about it:
Silence the warning. It is just a warning, after all; and I don't see a "typical mistake" (like typing 0 instead of your condition) that would be caught by this warning.
[edit] Now, that was silly. the typical mistake that you catch with the warning is e.g. while (a1!=a1) instead of while (a1!=a2).[/edit]
Break into functions, move state to a class
this would transform above code to:
struct Garbler
{
State1 state1;
bool Step1()
{
state1 = 0;
if (cond1())
{
if (cond2())
return false;
state1 = opA();
}
return true;
}
bool Step2()
{
return cond3() || state1 && state1->cond4();
}
..
void Run()
{
if (Step1() && Step2() && ... && Step23())
Triumph(state1, ...);
else
Failure(state1, ...);
}
}
This is arguably less readable, worse is that you pull apart the sequence, which might lead to a very questionable class (where members may be called only in a certain order).
Scopeguards
This may allow to transform the breaks into early returns, which are more acceptable:
state1 = 0;
ScopeGuard gFailure = MakeGuard(&Failure, ByRef(state1), ...);
if (cond1())
{
if (cond2())
return;
state1 = opA();
}
if (cond3() || state1 && state1->cond4())
return;
// everything went ok, we can dismiss the scopeguard
gFailure.Dismiss();
Triumph(state1, ...);
They can be more elegantly written in C++0x, preserve the flow, but the solution isn't that flexible either, e.g. when Failure() cannot be isolated easily into a single function.
Nested nested if-else statements can become quite unreadable, but I think using do {..} while(0); as a replacement would be much worse. It is very unconventional and anybody else reading it would not really associate it with if-else statements.
There are a few things you can do to make nested if-else statements more readable. A few suggestions are:
optimize your logic - sometimes you can do away with a lot of if clauses when you 'refactor' your logic ex. grouping identical items.
use switch() - switch is generally more readable compared to if-else statements. You can associate an enum to each case and you can switch this.
encapsulate complicated logic with functions
You can use goto instead of do {} while(0) and break. This is not readable and not good practice either though. I think for each specific case there is a better way to avoid deep if/else structures. For example, sometimes using function calls can help:
for example instead of:
if(status_of_funcA_ok != funcA())
{ //failure}
else if (status_of_funcB_ok != funcB())
{//failure}
else if (status_of_funcC_ok != funcC())
else
{//Great}
you can write:
if (check_funcs() == 0) {
great();
}
int check_funcs() {
if (status_of_funcA_ok != funcA())
return -1;
if (if(status_of_funcB_ok != funcB()))
return -2;
if (if(status_of_funcC_ok != funcC()))
return -3;
return 0; /* great */
}
Sometimes, you can use exit().
Also, in c++ you can use throw() and try/catch:
try {
/* */
throw (this error);
/* */
throw (that error);
} catch (this error) {
} catch (that error) {
}
If there are more conditions to check avoid using if{} else{},
best practice is to Replace if else conditions with switch case
While playing with NLP I've been encountered with little problem:
switch(var1)
{
case Variant1_1:
if( cond1 )
{
if( cond2 )
{
if( cond3 )
{
switch(var2)
{
case Variant2_1:
return someExpression;
// another five-six cases
default:
return;
}
}
else // cond3
{
switch(var2)
{
case Variant2_1:
return someExpression;
// another five-six cases
default:
return;
}
}
}
else // cond2
{
if( cond3 )
{
switch(var2)
{
case Variant2_1:
return someExpression;
// another five-six cases
default:
return;
}
}
else // cond3
{
switch(var2)
{
case Variant2_1:
return someExpression;
// another five-six cases
default:
return;
}
}
}
}
else // cond1
{
// same thing
}
break;
case Variant1_2:
// same gigantic tree
break;
case Variant1_3:
// here too
break;
default:
return;
}
What alternatives are for such "computational tree"? The only thing that comes to my mind - some tree container with function pointers as leaves and a great deal of little functions.
(tongue in cheek) Every time you encounter a switch statement in a C++ program, you know that you've missed an inheritance opportunity.
The two ways I know to refactor multiple parallel switches are (1) building a multi-dimension array of function pointers, and (2) using a variation of the visitor pattern.
A nice workaround is using a matrix.
This will work well if you know that all the conditions will be evaluated anyway.
Make a multi-dimensional array that will map the true-false values to the handling functions.
Arrayswitch[var1][cond1][cond2][cond3][var2]();
I start looking for a data-driven approach when code starts to look like this. It may be as simple as a table or perhaps a tree with function pointers as you've suggested.
If this is a hand-rolled parser of some sort, you might want to look into some references on parsing for ideas on how to use a grammar definition to do the parsing (either by interpretting the grammar on demand, or by using a code-generation tool that uses the grammar as input).
I often hand-roll recursive descent parsers. Typically, I create a class that holds the state, expose one public "Parse" function, and implement each rule as a private member function. These member functions are small and explicitly named, so the code becomes quite readable. It's also very easy to write tests for it.
Polymorphism and good code design.
http://www.cs.bu.edu/teaching/cpp/polymorphism/intro/
What you're describing is what the compiler will make out of your code anyway :) So you're essentially proposing a nested programming language, which brings about Greenspun's law: "Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp."
There are ways of writing this code better to express your conditions. when you have a lot of nested if() { if () { if() } } }s, usually just writing if (!condition) break; or other escaping method, simplifies the code. not always but a lot of times.
In a situation where a variable could have two different values, and you do something if its one, something differnent if its the other, would you just do:
if(myVariable == FIRST_POSSIBLE_VALUE) { ... }
else { ... }
or would you do:
if(myVariable == FIRST_POSSIBLE_VALUE) { ... }
else if (myVariable == SECOND_POSSIBLE_VALUE) { ... }
for clarity, in a situation where a reader wouldn't necessarily be able to tell that they do the same thing (but the else if does a "needless" expression)?
So what would you do?
Thanks!
EDIT: There is actually about a lot more different options for something like this: ternary operator, if-else, if-elseif, if-elseif-else, -if-else(with assert), switch. Each one has its place, but its hard to decide..
I always prefer just plain else when there is no other possible state of the variable(ie, checking for null and all that). I may add a comment saying what the variable is if it isn't the first conditional, but that is only in cases where its like
if(color==red){
....
}else{ //our theme only allows for red and yellow, so the color must be yellow.
....
}
Also, this saves some time for the processor cause it won't have to check a useless variable(or worse in OOP, where checking that variable can take quite a few dereferences, function calls, and memory reads)
I never do something like
if(file.is_open==1){
....
}else if(file.is_open==0){
....
}
as is_open is a boolean, it is pointless to specify that because the only option left is 0, also this can save a little bit of typing when you must refactor your code to use is_open() instead, as now you only must change one line instead of two.
and 'else if' statements I think should be turned to switches if there is more than 1 'else if', unless of course the language makes it impossible(such as how C can't handle strings in switches)
Else is a default. Meaning that there are either a large number of possibilities for the data, or that it is unexpected data.
I go by the basic rule: If there is a parameter that can be met, use else if, and if there isn't, use else. I normally use else's for errors.
I only use the if-else for boolean checks, that means that if the expression doesn't match there only can be the else. Or i want to take everything with the else: think of it like default.
If you want to check enumeration or something, you should try check this via switch statement, if possible in your language.
In Java it's not possible to use a switch for Strings. So you could use something like this:
if(string.equals("foo")) {
// first case
} else if(string.equals("bar")) {
// second case
} else {
throw IllegalArgumentException(" ... ");
// or log it
}
If you're not sure that your check can't be extended, you should if you can provide an default way.
Isn't this what assert was made for?
if (condition1) { ... }
else { assert(condition2); }
This can be expanded for three-state logic, too.
if (condition1) { ... }
elsif (condition2) { ... }
else { assert(condition3); }
Using assert makes your code readable, easy to maintain, and clear. That being said, asserts and comments are almost interchangeable.
Sometimes the condition of the else statement is very obvious. For example
if(user.IsNew) { } else { /*in this case user.IsNew != true*/ }
But in some other cases the else isn't that obvious and it is better to clarify the else condition. This is also more future proof in case some other possible conditions are added.
Furthermore you are able to insert an exception in the (last) else to inform about unimplemented cases. This can be very useful when the for example backend and frontend are separated and somebody adds a new value to an enumerator (or when using text keys a new key is introduced) you will receive an error when the new value is first used. When not using if else if you won't see what happened and that could make debugging pretty hard.
if(user.SelectedStyle == Styles.Red) {
} else if(user.SelectedStyle == Styles.Basic) {
} else {
throw new Exception("Not implemented");
}
In the case above a new Style (for example Style.Blue) will cause your application to throw an exception.
It's really a matter of style and your own mental view of the world. The glass is BOTH half empty and half full, but you can get the darnedest arguments going about it.
If the boolean tests are all of the same type, a switch statement is best.
If not, I'd recommend leaving out the additional test but insert a comment about the operational meaning of falling through into that last statement. See Gertjan's comment, above.
When your input can be clearly separate into distinct cases, I feel it is mostly nicer to explicitly state what those cases are, for example if you are expecting 'n' to be a number between 0 and 100, and you have 3 cases:
if (n >= 0 && n < 30) {
case1();
} else if (n >=30 && n < 70) {
case2();
} else if (n >=70 && n < 100) {
case3();
}
in some situations the 'else' case is good for error checking
} else {
error("n should be between 0 and 100");
}
if your data is checked for erroneous values earlier, then there may be a case to use else for the final case, to provide a small performance improvement in languages like C:
} else { // (n >= 70 && n < 100)
case3();
}
but this is only necessary due to some languages inability to express the domain of a function, in languages where the domain can be expressed clearly, the optimiser should add this performance benefit for you, allowing you to be specific in your code, and making it easier to add more cases later
... of course this is an art, not a science, and in some cases you can't follow the hard-and-fast rule, I frequently find myself writing code like:
if (p == NULL) {
doSomething();
} else {
doSomethingElse();
}
...justified by the fact that is very obvious and implicit from the first if condition what the else is used for.
else was invented and is used for good reason. Where you use it should be dictated by the logic that you trying to achieve, not a contrived sense of style.
Some argue that it is more self-documenting by using explicit conditions in an else if; however, this may lead to gaps in logic with default or catch all conditions.
Also, some say that it is easier to modify in the future. This argument is bunk. Using design patterns and writing modular code is something that is easier to modify in the future, writing one line shouldn't qualify for these kinds of statements.
It depends on the situation. Do you only want to take action if certain criteria are met, or is there a special case for one value and another set of logic for any other value?
I just hope the following doesn't seem to you like redundant jabber :)
Anyway, there is that:
for (p = fmt; *p; p++) {
if (*p != '%') {
putchar(*p);
continue;
}
switch (*++p) {
/* Some cases here */
...
}
}
And I wondered why the writer (Kernighan / Ritchie) used the continue in the if statement.
I thought it was for the mere reason that he deemed it would be more elegant than indenting the whole switch under an else statement, what do you think?
Probably. The human brain has limited stack space, making it difficult to deal with deeply nested structures. Anything that flattens the information we're expected to parse makes it easier to understand.
Similarly, I normally prefer this:
bool foo(int arg)
{
if(!arg) {
/* arg can't be 0 */
return false;
}
/* Do some work */
return true;
}
To this:
bool foo(int arg)
{
if(!arg) {
/* arg can't be 0 */
return false;
} else {
/* Do some work */
return true;
}
}
Or worse, to this:
bool foo(int arg)
{
if(arg) {
/* Do some work */
return true;
} else {
/* arg can't be 0 */
return false;
}
}
In the last example, the part that does the work might be quite long. By the time the reader gets to the else clause, he may not remember how he got there.
Putting the bail out conditions as close to the beginning helps to assure that people who try to call your functions will have a good idea of what inputs the function expects.
Also, as others pointed out, the continue makes it clear that there's no need to read further into the code inside the loop to determine whether any more processing is done after that point for this case, making the code easier to follow. Again, the fewer things you force the reader to keep track of, the better.
Because with the continue it is clear that the code is done for this loop iteration. If a else would have been used you had also to check if there is no code after the else.
I think it is general a good habit to exit a context as soon as possible because this leads to much clearer code.
For example:
if(arg1 == NULL)
return;
if(arg2 == NULL)
return;
//Do some stuff
vs.
if(arg1 != null)
{
if(arg2 != null)
{
//Do some stuff
}
}
It is just so much easier to read when it's put like this.
Are we done here with this iteration through the loop? Yes? So let us continue with the next iteration.
I think that he would have reasons enough to indent the code under the switch, and indenting the entire meat of the function is quite wasteful of horizontal space. At the time the code was written, I imagine 80 character widths were still popular.
I don't think it is difficult to understand, but I do think that it's quite nice to mention what you DON'T do immediately, and then GTFO.
There are always many ways to write code like this -
Putting the entire switch inside an else statement would be perfectly valid. I suppose the reason they did it this way ~may~ have been just the way they were thinking at the time:
"if the value at p does not equal '%', put then continue on."
If you have switch under an else, it may not have been as obvious to the writer that you were jumping to the next iteration in that specific case.
This is completely personal style choices, though. I wouldn't worry too much - just write it in a way that makes the most sense to you and your team.
I agree.
But you can't look at it as a "mere reason", it's actually a pretty good reason, because it reduces the over all complexity of the code. Making it shorter and easier to read and understand.
If you use an else then everything inside the else needs to be indented:
if ()
{
doA();
}
else
{
doB();
if ()
{
doC();
}
else
{
doD()
}
}
If you use continue then you don't need to indent:
if ()
{
doA()
continue;
}
doB();
if ()
{
doC();
continue;
}
doD();
Also, continue means that I can stop thinking about that case: for example, if I see else then perhaps there'll be more processing of the '%' case later in the loop, i.e. at the end of the else statement; whereas on seeing continue I know instantly that the processing of the '%' case in the loop is completely finished.
The most probable reason is that the switch that follows is rather long - this looks like printf format parsing.
There could be more that one reason to continue/break a loop. So it would look next:
loop
{
if (cond1)
{
if (cond2)
{
if (cond2)
{
more conditions...
}
}
}
else
{
the loop action
}
}
IMHO it's not so elegant and readable as the loop in your example, e.g:
loop
{
if (cond1)
continue;
if (cond2)
continue;
if (cond2)
continue;
if( more conditions...)
continue;
the loop action
}
And you don't even need to understand all structure of all "if"s (it could be much more complex) to understand the loop logic.
P.S. just for the case: I don't think the authors thought about how to write this loop, they just wrote it:)
I stick to Dijkstra's teachings: goto is harmful. And continue/break are goto's little brothers.
If the problem is that you're indenting the code too much, the solution is not putting a continue in the loop, but reducing the complexity by separating the code in different functions or thinking about a better way of organizing it.
For example, #Kamarey snippet would be even clearer like this:
loop
{
if (!(cond1 ||
cond2 ||
cond2 ||
...))
{
the loop actions;
}
}
or #Ori Pessach example could be expressed like:
bool foo(int arg)
{
if(arg) {
/*do some work*/
}
return arg != 0;
}
In brief, usually I can't find a good enough reason to use non structured programming constructs (maybe for some cleanup codes in a very limited ocasions...)
Well, I wrote C programs for about 11 years and I had to read 5 times your piece of code to understand it !
Kernighan and Ritchie were active in the sixties. At that time, being able to understand a piece of code was not relevant. Being able to write code that fit in 16 Ko was.
So I'm not suprised. C is a terrible language when your teatchers are K & R. Just look at realloc : who would know code something like that today ? In the '60ies, it was all the rage, but it is now appalling, at least :o)