Solving the nested if nightmare

August 07 2010
c#

I recently read a question on a forum I frequent asking about the different ways people handle nested-if's.

I was doing something today, (C#, but it probably doesn't matter that much), where literally hundreds of statements relied on the previous being successful. At first, I started using simple nested ifs, but it just got out of hand real quick. I mean, it was in VS which handles formatting nicely, (if I was at working using the Borland C++ 5 IDE like I do at work I'd be screwed), but it's still not going to cut it; I will have to come back and read this one day and I won't be able to make sense of it if I have to scroll across etc. just to read each bit.

So then I thought, well, I could have a boolean that I set true or false given the outcome of a call, and then put it in the if statement for the next; thereby bypassing all future calls. This keeps everything nicely in line, and reasonably readable, but then I thought, well heck, I could just use a for loop and break out of it. I know it seems dodgy; break and continue are not dissimilar to goto calls; but it just looks a lot cleaner.

Then I also thought I could just throw a new exception that I make myself, and just catch it at the end of the function. That's what I decided to go with in the end because I thought it was probably the *correct* way to do it, but I did think that perhaps it may be more computationally expensive than a simple break, (in this case it probably didn't matter).

What would you do, (please let me know language etc. too)?


Link here

I'm not a fan of exceptions in these situations because exceptions are supposed to be for exceptional situations and  there is an overhead associated with throwing exceptions (a cost a number of orders of magnitude greater! in C#). I also don't approve of throwing exceptions during validation (which may be a situation similar to what you're doing here?).

Is there a better way you could be controlling program flow? Are some of the conditionals actually guard clauses (often by inverting them)? Is it possible to use polymorphism to refactor the conditionals, similar to using polymorphism to refactor switch statements (seeing as if's could also be switches) ?

Here's the basic problem


class Program
{
static void Main(string[] args)
{
bool condition1 = true;
bool condition2 = true;
bool condition3 = true;
bool condition4 = true;
bool condition5 = true;
if (condition1)
{
if (condition2)
{
if (condition3)
{
if (condition4)
{
if (condition5)
{
DoSomethingImportant();
}
}
}
}
}
}
}

You can see that maintainability is already difficult and as the conditions for execution increase the problem only increases.  In some cases we can reverse the conditions and use guard conditions instead.

class Program
{
static void Main(string[] args)
{
bool condition1 = true;
bool condition2 = true;
bool condition3 = true;
bool condition4 = true;
bool condition5 = true;
if (!condition1) return;
if (!condition2) return;
if (!condition3) return;
if (!condition4) return;
if (!condition5) return;
DoSomethingImportant(); }
}

The guard statements get executed and nesting has been removed.  In some cases we could stop here, although when using hundreds of conditions, readability is still poor.  Seeing as we're using C#, an object oriented language, we can refactor the conditions as Commands and build up a composite command object that executes each command condition before calling the final desired action.


public interface ICommand
{
bool Execute();  
}

Now the conditions implementing the command pattern.


public class Condition1 : ICommand
{
public bool Execute()
{
return true;
}
}

public class Condition2 : ICommand
{
public bool Execute()
{
return true;
}
}

public class Condition3 : ICommand
{
public bool Execute()
{
return true;
}
}

public class Condition4 : ICommand
{
public bool Execute()
{
return true;
}
}

public class Condition5 : ICommand
{
public bool Execute()
{
return true;
}
}

And the action we want to execute when all conditions are met

public class DoSomethingImportant : ICommand
{
public bool Execute()
{
// Do Something Important
return true;
}
}

And finally a class that encapsulates a conditionally executed command

public class ConditionalCommand : List<ICommand>, ICommand
{
public ConditionalCommand(ICommand action, params ICommand[] conditions) : base(conditions)
{
base.Add(action);
}
public bool Execute()
{
foreach (var cmd in this)
{
if (!cmd.Execute())
{
return false;
}
}
return true;
}
}

Now we input our conditional commands and desired action and execute


class Program
{
static void Main(string[] args)
{
var action = new ConditionalCommand(
new DoSomethingImportant(),
new Condition1(),
new Condition2(),
new Condition3(),
new Condition4(),
new Condition5());
action.Execute();
}
}

Post a comment

comments powered by Disqus