You are asking the wrong question
You have asked about alternatives for your nested-ifs but I believe this is a case of a XY Question.
The XY problem is asking about your attempted solution rather than your actual problem.
That is, you are trying to solve problem X, and you think solution Y would work, but instead of asking about X when you run into trouble, you ask about Y.
I believe that the true question you are facing is one about clean code/ code quality.
Asking how to rewrite nested-ifs is just your current attempt at trying to clean the FooBar
function. As a result, I will attempt to answer the following question:
How can I improve the code quality of my FooBar
function?
For my answers, I will be referencing and quoting the brilliant must-read book by Robert C. Martin Clean Code: A Handbook of Agile Software Craftsmanship
Your functions should do one thing
Take a look at your example. Does it look that it does only one thing?
static ErrorCode_t FooBar (Input_t input)
{
ErrorCode_t errorCode = FAIL;
if (condition1IsNotMet) {
errorCode = ERROR_CODE_1;
} else {
// doSomethingHere
if (condition2IsNotMet)
errorCode = ERROR_CODE_2;
else
// doAnotherThingHere
}
return errorCode;
}
It doesn't.
And the various if-elses dividing the code into big chunks is a good indication of so. Your code clearly has sections, making them inherently more complex to reason.
Functions should do one things. They should do it well. They should do it only.
Your functions should be small
Functions should Hardly be 20 lines long.
in fact, most functions could be expected to be less than 10 or even less than 5 lines long. Wait! How am I going to write a nested-if with so few lines? Well, Robert C. Martin writes:
(...) blocks within if
statements, else
statements, while
statements, and so on should be one line long. Probably that line should be a function call. Not only does this keep the enclosing function small, but it also adds documentary value because the function called withing the block can have a nicely descriptive name.
This also implies that functions should not be large enough to hold nested structures. (...)
Refactoring your code
Using these two principles, it should be clear that the doSomethingHere
and doAnotherThingHere
should be independent functions and that we need to break your nested if. It would end up looking something like this:
static ErrorCode_t FooBar(Input_t input)
{
if (condition1IsNotMet)
return ERROR_CODE_1;
return DoSomethingHere(input);
}
static ErrorCode_t DoSomething(Input_t input)
{
// doSomethingHere
return HandleMoreThings(input);
}
static ErrorCode_t HandleMoreThings(Input_t input)
{
if (condition2IsNotMet)
return ERROR_CODE_2;
return DoAnotherThing(input);
}
static ErrorCode_t DoAnotherThing(Input_t input)
{
// doAnotherThingHere
return FAIL;
}
How you break up your functions depend of the one thing they do
I can only speculate about the behavior of your code. But now we can ask the questions for each one of the smaller functions:
static ErrorCode_t FooBar(Input_t input);
static ErrorCode_t DoSomething(Input_t input);
static ErrorCode_t HandleMoreThings(Input_t input);
static ErrorCode_t DoAnotherThing(Input_t input);
For each one of them, what is the expected result?
The final code may vary according to the actual intent of your code.
For example, you could argue that the code should be written as:
static ErrorCode_t FooBar(Input_t input)
{
if (condition1IsNotMet)
return ERROR_CODE_1;
result = DoSomethingHere(input);
if(result == SUCCESS);
return ERROR_CODE_2
else
return FAIL;
}
static AnotherErrorCode_t DoSomething(Input_t input)
{
// doSomethingHere
return HandleMoreThings(input);
}
static AnotherErrorCode_t HandleMoreThings(Input_t input)
{
if (condition2IsNotMet)
return SUCCESS;
DoAnotherThing(input);
return FAIL;
}
static void DoAnotherThing(Input_t input)
{
// doAnotherThingHere
}
I cannot tell without the details.
The one thing your code does cannot be told by only looking at its conditional statements. Hence, you will need to adapt this answer to your code using your best judgment.
A note about the "only one return statement" constraint
In the end of your question, you have added:
Please note my requirements before marking as duplicate. I need to have a single return. I need to have behavior occur between condition checking. Also note the rationale behind a single return (though I do not agree) is for readability, not performance.
By actually dividing your functions in smaller chunks, you get readability without that artificial rule of "having only one return in the end". in fact, that rule seems to be an artificial attempt to solve a "bad code" problem.
Also, even if you have to follow the one return at the end rule (perhaps because of a company guideline), it is much easier to do so if you divide your code into smaller chunks.
Bottom Line
The problem is neither having multiple returns or writing the nested-ifs in a good way.
The problem is that multiple returns indicate that your code does not do one thing only. Same thing for the nested-ifs.
By organizing your code in smaller chunks, you will get a better code.