I recently ran against a very interesting site that expresses a very interesting idea - the anti-if campaign. You can see this here at www.antiifcampaign.com. I have to agree that complex nested IF statements are an absolute pain in the rear. I am currently on a project that up until very recently had some crazy nested IFs that scrolled to the right for quite a ways. We cured our issues in two ways - we used Windows Workflow Foundation to address routing (or workflow) concerns. And we are in the process of implementing all of our business rules utilizing ILOG Rules for .NET (recently purchased by IBM!!). This for the most part has cured our nested IF pains...but I find myself wondering how many people cure their pains in the manner that the good folks at the AntiIfCampaign suggest (see an example here) by creating numerous amounts of abstract classes to represent a given scenario that was originally covered by the nested IF. I wonder if another way to address the removal of this complexity might also be in using an IoC container such as StructureMap to move in and out of different bits of functionality. Either way...

Question: Given a scenario where I have a nested complex IF or SWITCH statement that is used to evaluate a given type of thing (say evaluating an Enum) to determine how I want to handle the processing of that thing by enum type - what are some ways to do the same form of processing without using the IF or SWITCH hierarchical structure?

16 Answers
16

The problem is not the 'if' statement, it is the programmers who write bad code.

EDIT: Also, as others have pointed out, you should be using polymorphism (if available) when you are using if statements to check the type of an object, but if statements in and of themselves are very useful and fundamental constructs.

Can any of you suggest good code to the programmers that write bad code?
–
Andrew SiemerJul 22 '09 at 19:42

1

@IRBMe: Yes, polymorphism should be used when you are checking the type of an object, but you can't use it in all circumstances. If I want to know whether or not an integer is less than 0, I'm using an 'if' dammit! :-)
–
Ed S.Jul 22 '09 at 19:44

My question here though is how do I know which widget do I want to use without evaluating the type of widget that I need to process? I can see using interfaces and and a WidgetFactory to return the appropriate widget...but inside that WidgetFactory (or somewhere) wouldn't I still have some evaluation type code to help me decide which widget to return/use?
–
Andrew SiemerJul 22 '09 at 19:31

1

This doesn't really answer the question. It just means that instead of deciding which code to invoke, you have to decide which class to instantiate, which contains the code you want to invoke. You would have to do something like place instances of each class in some sort of mapping data structure (such as a Dictionary), which maps the widget type to the correct object. I gave an example of that in my answer. Also, the base class should probably be an interface.
–
IRBMeJul 22 '09 at 19:39

You can use the Command Pattern to perform commands based on some value or input.

In answer to your question, you can use a simple lookup table or polymorphism to achieve this, although it places the logic in a different part of the program, which may indeed be the correct thing to do. Here are a couple of examples in C#:

This usage of command is not helpful here, as it is still making your code violate the Open/Close principle, which is the problem in most conditional structures like the one mentioned. With the IF or your command chain, if you add any widget type later on you have to come to this code, OPEN it and add an additional handler. By using an interface or abstract class you just need to create a new implementation and pass it, with no logic change.
–
Martin SaliasDec 28 '10 at 20:48

Sometimes replacing a conditional via polymorphism is the right thing to do, but in those cases it wasn't the if statement that was the true problem. The real problem was working with abstract types in non-abstract ways, i.e., failing to think at level of abstraction of the base class.

Other times it is possible to replace a conditional via polymorphism, but doing so would be a bad idea. The logic that leads you to treat one type different from another may belong in the algorithm itself, not the individual classes. Moving that logic to the classes may cause the classes' code to be overly aware of the context in which they are used.

But most often, an if statement has nothing to do with polymorphism at all. Getting rid of if statements is the wrong goal here.

Hence my post! I was wondering how people address the simple case above as in my thinking I can't see a clear way to do this. I am hoping to be enlightened!...as I can't think of a single project I have ever done that didn't have something similar or more complex in it which I would love to get rid of.
–
Andrew SiemerJul 22 '09 at 19:29

I am now reading about an anti-for approach!
–
Andrew SiemerJul 22 '09 at 19:29

2

Okay, so there are replacements. Frankly, I find these replacements more unreadable than the original code.
–
KawaJul 22 '09 at 19:33

That depends on amount of nested ifs I guess. And if what they do can be separated and isolated into table of functions or polymorfic objects. This is "do one thing" again. I find that a lot of nested ifs can be eliminated just by returning early.
–
EugeneJul 22 '09 at 19:39

Dijkstra beat you to the anti-goto campaign. See Also: GoTo Statement Considered Harmful.
–
PowerlordJul 22 '09 at 19:45

It depends on how you handle the situation. If you called a different function using the same signature, you could have a dictionary where the key would be the type and the value a delegate pointing to the real handler. Thus you can get rid of the switch and just do

Polymorphism is the right way to go when the logic must be baked into the classes.

But since many applications these days already interact with their own database, another solution is to use table-based logic. Advantages of using tables:

Adjust business logic without recompile.

Database instances can share the same code but different logic.

I'm not talking about directly embedding source code in a database varchar() field and compiling it on the fly.

But let's say you have a list of input fields, and for each one, you need to perform (a) some RegEx to scrub the value, and (b) one or more tests to validate the result.

In a code-only world, you would have a subclass for each type of field, each implementing, say, it's own methods called ScrubValue() and Validate().

In a table-based pattern, a single Field class would reach into the database (cached of course) based on a FieldType property and retrieve a set of RegEx search/replace strings, and a list of validation test parameters (minimum and maximum length, regex patterns to match, etc.).

This works well for any situation where the number of subtypes is increasing over time and the logic can be expressed as a set of configurable strings, numbers, etc. rather than having to be directly implemented as code.

I was about to write about tabular code, tables are very easy for humans to parse and understand. Easier than both ifs and polymorphism if you ask me! This might require storing code in a DB or using a language in which code is a first class citizen such as a lisp.
–
sandosJun 11 '14 at 7:50

You could try catch absolutely every exception possible when you go down the wrong execution path until you hit a path of execution that DOESN'T break, but that is FAR worse than if's.

You can use a Command pattern or a Map for when object-orientation and polymorphism is natural, but what if you're dealing with outcomes from user input that are complex and NOT in and of themselves objects?

Implementing that idea in a C-like language is very lame... but in a proper functional language with guarded pattern matching is much more idiomatic and a richer way to express conditionals, I dare to add.

I think I understand what they mean. We probably won't survive without if's and switches, but it is true that deeply nested conditional blocks are a pain to read.

An example from my own job: a function to calculate the simulated strain of a shunted wheatstone bridge. This function takes like 5 configuration parameters (which shunt branch, are there any shunt sense lines, supply sense lines, ...), and I wasn't quite looking forward to writing the dispatching routine.

I came up with a templated code structure that allowed me to 'declare' the proper functions (about 30 or so) instead of having to crunch them into one dispatching routine.

This enabled us to very quickly add new configuration parameter cases, and kinda 'copy' the equations from the mathematical overview. Quite a win, really.

Once your if statements start becoming big and nested, one of the possiblities may be that the number of conditions you have to test has grown. In that case, as you add more conditions to the situation it starts becoming exponentially easier to let some combination of conditions fall through the cracks, and then bam, you've got yourself a bug.

I always thought in cases like these, some kind of truth table would be good. About the closest approximation I can come up though ends up being kind of baffling to the average programmer. It involves assembling all your conditions into a single integer, and then trying to cover every number in the range that creates with either a switch statement or a lookup table.

I'm not sure polymorphism is the right answer for this one though. Anyone got any better ideas?