More and more I find myself writing a structure of If statements that looks like this:
if(something) {
if(somethingElse) {
// If both evaluate to true.
doSomething();
}
else {
// If the first if is true but the second is not.
doSomethingElse();
}
}
else {
// If the first evaluates the false.
doSomethingDifferent();
}
Now, to me, this looks horrific. Does anyone have a cleaner way of representing this logic?
The question as-is has three cases: something & somethingelse, something & !somethingelse, and !something. The alternative is to break it out into an if-else with three branches:
if(something & somethingElse) {
// If both evaluate to true.
doSomething();
}
elif(something) { // explicit test of somethingElse falsity not required
// If the first if is true but the second is not.
doSomethingElse();
}
else {
// If the first evaluates the false.
doSomethingDifferent();
}
For such a simple case, I usually prefer to flatten the structure as above. For more complex cases, it can end up being simpler to nest, or even better to reduce your tests to some kind of structure (a list or integer depending on your language) and switch on that value.
Related
The style of this is certainly questionable, but I'm curious if there is a "clean" way in C++ to do a refactor like the following.
Suppose we start with the working code:
if (shapeA.intersects(shapeB)) {
// ... lots of code
} else {
// lots more
}
And I want to do a quick and dirty comparison with my new intersection routine, I'd like to inject a ternary into this if conditional:
if (shapeA.(enable_opt ? intersects_optimized : intersects)(shapeB)) { // expected unqualified-id
// hooray, we are undisturbed
} else {
// lots more
}
As opposed to the pretty awful looking
if (enable_opt) {
if (shapeA.intersects_optimized(shapeB)) {
// ... lots of code
} else {
// lots more
}
} else {
if (shapeA.intersects(shapeB)) {
// trail of tears
} else {
// despair and suffering
}
}
The pain/ugliness involved scales somewhat with the complexity of the conditional inside...
I've tried a few ideas and although it seems like member function pointers are possible to use, it appears impossible to specify a particular overload when obtaining the function pointer for a member variable if that function name is overloaded.
There's a possible 'halfway-house' solution using the ternary which, although still repeating some code, involves only one if ... else test:
if (enable_opt ? shapeA.intersects_optimized(shapeB) : shapeA.intersects(shapeB)) {
// hooray, we are undisturbed
} else {
// lots more
}
Not sure if you count this as 'ugly' or not, though.
You could possibly do it by selecting between pointers-to-member-function, but it wouldn't be very pretty.
Just wrap the call:
bool TestShapeIntersection(const Shape& a, const Shape& b)
{
if (enable_opt)
return a.intersects_optimized(b);
else
return a.intersects(b);
}
Then:
if (TestShapeIntersection(shapeA, shapeB)) {
// hooray, we are undisturbed
} else {
// lots more
}
You can write the ternary as
if ((shapeA.*(enable_opt ? &Shape::intersects_optimized : &Shape::intersects))(shapeB)) {
// hooray, we are undisturbed
} else {
// lots more
}
But it is not a lot prettier.
Note that
you cannot drop the &Shape:: part;
you need the additional pair of parentheses;
it is not exactly idiomatic.
The alternatives that move the call into a helper function are preferable.
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);
I have code that does something like this:
//datareader.cpp
if (populateFoo(dataReader, foo))
else {
// Do other things with the reader.
}
//foo.cpp
bool populateFoo(const DataReader &dataReader, Foo &foo)
{
if (dataReader.name() == "bar") {
foo.bar() = dataReader.value();
return true;
} // More similar checks.
return false;
}
I feel like it's misleading to have an if statement with conditions that have side-effects. However, I can't move the body of the populateFoo function into datareader.cpp. Is there a good way to restructure this code so we get rid of this misleading if statement, without duplicating the body of populateFoo()?
Do you have a strong hatred of local variables? If not:
bool populated = populateFoo(dataReader, foo);
if (populated)
{
// Do things
}
else
{
// Do other things
}
The compiler will almost certainly emit exactly the same code, so performance shouldn't be an issue. It's a readability/style choice, ultimately.
The obvious solution seems like storing the result of populateFoo and using it for determining whether populateFoo was successful:
bool fooPopulated = populateFoo(dataReader, Foo);
if (!fooPopulated)
//Do other things with reader.
However, I don't find the original difficult to understand, and it's a fairly well-established practice to both modify values and test the success of the modification in the same line. However, I would change it to:
if (!populateFoo(dataReader, Foo)
//Do other things with reader.
How about:
if (!populateFoo(dataReader, foo)) {
// Do other things with the reader.
}
Edit: The title of the question suggests it is the fact the if statement is empty that bothers you but the body seems more that it is the side effect that is the concern. I think it's fine in C++ to have conditions in if statements that have side effects but this won't solve your issue if you want to avoid that.
Having conditions with side-effects is quite common - think about calling a C API and checking its return code for errors.
Usually, as long as it's not buried in a complicated expression where it may be missed by the casual bystander, I don't bother to do particular refactorings, but, in case you wanted to make it extra clear (or document what the return value is, which is particularly useful in case of booleans) just assign it to a variable before the branch - or even just a few comments may help.
You could split the populateFoo function into two, a const check function (shouldPopulateFoo) that checks the condition, and another non-const function that performs the actual modifications (populateFoo):
//datareader.cpp
if (shouldPopulateFoo(dataReader)) {
populateFoo(dataReader, foo);
}
else {
// Do other things with the reader.
}
//foo.cpp
bool shouldPopulateFoo(const DataReader &dataReader) /* const */
{
return (dataReader.name() == "bar");
}
void populateFoo(const DataReader &dataReader, Foo &foo) /* non-const */
{
assert(shouldPopulateFoo(dataReader));
foo.bar = dataReader.value();
}
Note that when using these functions as class methods, you could declare the check function const.
How about:
if (populateFoo(dataReader, foo) == false) {
// Do other things with the reader.
}
It is very readable, I often see code where the returned value from function is a signal to the caller for branching in the caller. The else block with empty if block bothers me more then the side effects inside the if (). There is a sense of reverse logic, which is alway less readable.
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
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)