Patterns for Selection

Joseph Bergin

You are at a point in a program at which one of two or more different actions must be performed. You must select between the alternatives.

Whether or Not

You are in a situation in which some action may be appropriate or inappropriate depending on some testable condition.

Use an IF statement without an ELSE part, expressing the test condition positively if possible.

For example. In a power plant simulation, it may be necessary to shutdown a generator when it overheats.


if (measuredHeat > 200)
	shutDownGenerator();

Alternative Action

You are in a situation in which one of exactly two actions is appropriate depending on some testable condition.

Use a single IF statement with an ELSE part, expressing the test in positive terms.

For example a student may pass or fail an exam depending on the value of the numeric grade.


if ( numericGrade > 60 )
	output ("passing");
else
	output("failing");

(due to Rick Mercer)

Express Positive Conditions

You are applying Alternative Action and are wondering how to define the condition and lay out the IF-ELSE statement.

When writing conditions, express them positively whenever possible.

For example, suppose you have a robot simulation in which the robot must move but must also contend with obstructions in the path. Suppose you have a boolean test:


boolean frontIsBlocked();

Suppose that you want to move if possible, but turn Left instead if it is impossible to move forward. The following are equivalent:


if( frontIsBlocked()) 
	turnLeft();
else
	move();

if ( ! frontIsBlocked())
	move();
else
	turnLeft();

The first version is more readable and is preferred. It expresses a positive condition.

It may be desirable to write a function reversing the logical sense of a given test to apply this rule in all circumstances. For example here, one could write the function


boolean frontIsClear() { return ! frontIsBlocked() }

and use this in place of ! frontIsBlocked(). This makes it possible to Express Positive Conditions even when using other selection patterns than Alternative Action.

Note that the name chosen in the above, frontIsClear, is itself expressed positively. This is preferred over the equivalent frontIsNotBlocked.

Use Functions for Complex Actions

You are applying Whether or Not or Alternative Action and trying to layout the IF statement. You realize that one or more of the actions is complex.

Write a function to encapsulate the complex action(s). This is especially effective if you can choose a good name that captures exactly the nature of the complex action. This should then become the name of the function.

Write the Short Case First

You are applying Alternative Action and trying to lay out the IF-ELSE statement. One of the actions can be expressed simply in a statement or two. One is much longer. For some reason it is not desirable to apply Use Functions for Complex Actions.

Arrange the code so that the short case is written as the if (not the else) part.


if (someCondition())
	// aStatement
else
{ 	...
	// lots of statements
	...
}

This will permit the reader to easily dispense with one case before forgetting the condition that is used to choose between cases.

Range of Possibilities

You are thinking of applying Alternative Action, but you have more than two possibilities. You must choose exactly one of several actions to perform based on some condition.

If you have a situation in which the choices to be made depend on the current value of a single variable and that variable has a discrete (integer) type use a switch statement with the variable as the test value.


switch (skyColor)  
{	default: ... break;
	case Color.red: ... break; 
	case Color.blue: ... break;
	case Color.green: ... break;
}

Each case should end with break. Consider writing the default case first so that it may be easily seen and considered. If a break after a case is not appropriate, so that execution should continue through the next case, be sure to document that fact.


switch (skyColor)  
{	default: ... break;
	case Color.red: ... break; 
	case Color.blue: ... // No break. Continuing.
	case Color.green: ... break;
}

Be sure to include a break after the last case. Chances are that the switch will be extended in the future.

Sequential Choices

If the above situation does not apply (value of a discrete variable), but each action depends on a single testable condition, then you may need to write a sequence of IF's, where each IF but the last has an ELSE part that consists entirely of another IF.


if (myObject == bigObject())
{	...
}
else if (myObject == mediumObject())
{	...
}
else if (myObject == smallObject())
{	...
}
else
{	... // default case. 
}

Independent Choices

You are in a situation in which exactly one action must be chosen, but which action depends on several factors, not just a single one.

If the factors to be considered are independent and there are only a few such factors (three or less) then nested IF statements may be an adequate solution. Two factors that are independent of each other provide for four possibilities when taken together. For example if the factors are (rectangle or not) and (has background or not) then we get the four possibilities shown in Figure 1. Three independent factors will similarly result in eight possibilities.

Figure 1. Two independent choices

Another example is one in which you have two variables and you must decide on one action depending on whether each of these variable is negative or not. The following nested IF structure will work in this case. Here we have chosen to consider the x variable first and then the y variable.


	if(x >= 0)
	{	if(y >= 0)
		{	System.out.println("First");
		}
		else
		{	System.out.println("Second");
		}
	}
	else
	{	if(y >= 0)
		{	System.out.println("Third");
		}
		else
		{	System.out.println("Fourth");
		}
	}

Note that the structure of the inner IF is repeated in both parts of the outer IF , though the actions are not the same.

However, if we reverse the inner and outer structures we must proceed differently.


	if(y >= 0)
	{	if(x >= 0)
		{	System.out.println("First");
		}
		else
		{	System.out.println("Third");
		}
	}
	else
	{	if(x >= 0)
		{	System.out.println("Second");
		}
		else
		{	System.out.println("Fourth");
		}
	}

If you have three actions instead of four, but the choice depends on two independent factors, choose one or the other of the above nested structures so that one of the inner if's applies the same action in both cases. Then you can omit the inner test and just apply that action.

Often it is better to apply Use Functions for Complex Actions instead of nesting structures. To apply this in this case, let each inner IF be represented by a separate function call. You will need to write two functions to apply this: one for the IF part of what is here the outer IF and another for the ELSE part.

Sometimes you have several things to consider, but only two possible actions. In this case you need a compound expression to test. Apply the pattern Use Functions for Compound Boolean Expressions. Write a function that returns true when one of the required combinations of conditions is met and call this function as the test in the IF.