Decisions, Decisions

What will we cover?

The 3rd of our fundamental building blocks is branching or conditional statements. These are simply terms to describe the ability of our programs to execute one of several possible sequences of code (branches) depending on some condition.

Back in the early days of Assembler programming the simplest branch was a JUMP instruction where the program literally jumped to a specified memory address, usually if the result of the previous instruction was zero. Amazingly complex programs were written with virtually no other form of condition possible - vindicating Dijkstra's statement about the minimum requirements for programming. When high level languages came along, a new version of the JUMP instruction appeared called GOTO. In fact QBASIC, which can still be obtained from www.qbasic.net still provides GOTO and, if you happen to have QBASIC installed, you can try it out by typing the following bit of code:

10 PRINT "Starting at line 10"
20 J = 5
30 IF J < 10 GOTO 50
40 PRINT "This line is not printed"
50 STOP

Notice how even in such a short program it takes a few seconds to figure out what's going to happen. There is no structure to the code, you have to literally figure it out as you read it. In large programs it becomes impossible. For that reason most modern programming languages, including Python, VBScript and JavaScript, either don't have a direct JUMP or GOTO statement or discourage you from using it. So what do we use instead?

The if statement

The most intuitively obvious conditional statement is the if, then, else construct. It follows the logic of English in that if some boolean condition (see below for more about this aspect of things) is true then a block of statements is executed, otherwise (or else) a different block is executed.

Python

The GOTO example above looks like this in Python:

import sys  # only to let us exit
print( "Starting here" )
j = 5
if j > 10:
    print( "This is never printed" )
else:
    sys.exit()

Hopefully that is easier to read and understand than the previous GOTO example. Of course we can put any test condition we like after the if, so long as it evaluates to True or False, i.e. a boolean value. Try changing the > to a < and see what happens. Also notice the colon (:) at the end of both the if and else lines. As with loops the colon tells Python that a block of code is coming up, and the indentation tells it when the block starts and stops.

VBScript

VBScript looks quite similar:

<script type="text/vbscript">
MsgBox "Starting Here"
DIM J
J = 5
If J > 10 Then
    MsgBox "This is never printed"
Else
    MsgBox "End of Program"
End If
</script>

It's very nearly identical, isn't it? The main differences are that the word Then is required for the first block and we use End If to indicate the end of the complete if/else construct. (This use of an end marker is a common VBScript idiom, you may recall that we similarly had to use Loop to finish a VBScript Do While loop?)

And JavaScript too

And of course JavaScript has an if statement too:

<script type="text/javascript">
var j;
j = 5;
if ( j > 10 ){
    document.write("This is never printed");
    }
else {
    document.write("End of program");
    }
</script>

Notice that JavaScript uses curly braces to define the blocks of code inside the if part and the else part. Also the boolean test is contained in parentheses and there is no explicit keyword then used. On a point of style, the curly braces can be located anywhere, I have chosen to line them up as shown purely to emphasize the block structure. Also if there is only a single line within the block (as we have here) the braces can be omitted entirely, they are only needed to group lines together into a single block. However, many programmers like to always include the braces since they avoid inconsistencies and avoid having to go back and add them if we add one extra line to a block.

Boolean Expressions

You might remember that in the Raw Materials section we mentioned a Boolean type of data. We said it had only two values: True or False. We very rarely create a Boolean variable but we often create temporary Boolean values using expressions. An expression is a combination of variables and/or values combined by operators to produce a resultant value. In the following example:

if x < 5:
  print( x )

x < 5 is the expression and the result will be True if x is less than 5 and False if x is greater than or equal to 5.

Expressions can be arbitrarily complex provided they evaluate to a single final value. In the case of a branch that value must be either True or False. However, the definition of these two values varies from language to language. In many languages False is the same as 0 or a non-existent value (often called NULL, Nil or None). Thus an empty list or string evaluates to false in a Boolean context. Python works this way and this means we can use a while loop to process a list until the list is empty, using something like:

while aList:
   # do something here

Or we can use an if statement to test whether a list is empty without resorting to the len() function like this:

if aList:
   # do something here

Finally, we can combine Boolean expressions using Boolean operators which can often cut down the number of if statements we need to write.

Consider this example:

if value > maximum:
   print( "Value is out of range!" )
else if value < minimum:
   print( "Value is out of range!" )

Notice that the block of code executed is identical. We can save some work, both for us and for the computer, by combining both of the tests into a single test like this:

if (value < minimum) or (value > maximum):
   print( "Value is out of range!" )

Notice we combined both tests using a boolean or operator. This is still a single expression because Python evaluates the combined set of tests to a single result. You can think of it as evaluating the first set of parentheses, then the second set of parentheses and finally combines the two calculated values to form the final single value, either True or False. (In practice Python uses a slightly more efficient technique known as short-circuit evaluation which we discuss in the Functional Programming topic)

Very often if we think carefully about the tests we need to carry out in our natural language then we will find ourselves using conjunctions like 'and', 'or' and 'not'. If so there's a very good chance we can write a single combined test rather than many separate ones.

Chaining if statements

You can go on to chain these if/then/else statements together by nesting them one inside the other. Here is an example in Python:

# Assume price created previously...
price = int(input("What price? "))
if price == 100:
    print( "I'll take it!" ) 
else:
    if price > 500:
        print( "No way Jose!" )
    else:
        if price > 200:
            print( "How about throwing in a free mouse mat?" )
        else:
            print( "price is an unexpected value!" )

Note 1:we used == (that's a double = sign) to test for equality in the first if statement, whereas we use = to assign values to variables. Using = when you mean to use == is one of the more common mistakes in programming Python, fortunately Python warns you that it's a syntax error, but you might need to look closely to spot the problem.

Note 2:A subtle point to notice is that we perform the greater-than tests from the highest value down to the lowest. If we did it the other way round the first test, which would be price > 200 would always be true and we would never progress to the > 500 test. Similarly if using a sequence of less-than tests you must start at the lowest value and work up. This is another very easy trap to fall into.

VBScript & JavaScript

You can chain if statements in VBScript and JavaScript too but as it's pretty self evident I'll only show a VBScript example here:

<script type="text/vbscript">
DIM Price
price = InputBox("What's the price?")
price = CInt(price)
If price = 100 Then
   MsgBox "I'll take it!" 
Else
    If price > 500 Then
        MsgBox "No way Jose!"
    Else
        If price > 200 Then
            MsgBox "How about throwing in a free mouse mat too?"
        Else
            MsgBox "price is an unexpected value!"
        End If
    End If
End If
</script>

The only things to note here are that there is an End If statement to match every If statement and that we used the VBScript conversion function CInt to convert from the input string value to an integer.

Case statements

One snag with chaining, or nesting if/else statements is that the indentation causes the code to spread across the page very quickly. A sequence of nested if/else/if/else... is such a common construction that many languages provide a special type of branch for it.

This is often referred to as a Case or Switch statement and the JavaScript version looks like:

<script type="text/javascript">
function doArea(){
   var shape, breadth, length, area;
   shape   = document.forms["area"].shape.value;
   breadth = parseInt(document.forms["area"].breadth.value);
   len     = parseInt(document.forms["area"].len.value);
   switch (shape){
       case 'Square': 
           area = len * len;
           alert("Area of " + shape + " = " + area);
           break;
       case 'Rectangle': 
           area = len * breadth;
           alert("Area of " + shape + " = " + area);
           break;
       case 'Triangle':
           area = len * breadth / 2;
           alert("Area of " + shape + " = " + area);
           break;
       default: alert("No shape matching: " + shape)
       };
}
</script>

<form name="area">
<label>Length:  <input type="text" name="len"></label&lgt;
<label>Breadth: <input type="text" name="breadth"></label>
<label>Shape:   <select name="shape" size=1 onChange="doArea()">
           <option value="Square">Square
           <option value="Rectangle">Rectangle
           <option value="Triangle">Triangle
         </select>
         </label>
</form>

OK, Don't panic! I admit I've been a bit naughty and introduced a few new elements but there's nothing here to worry about. It is really just a slight extension to what you already know. The HTML form at the bottom has two text input fields to capture the length and breadth. The third input field is a new one, it is a drop down list of values and we have attached an onChange attribute that calls a function. All the fields have associated labels. It will look like this:

The HTML form code just allows us to capture the details and then when the user selects a shape it calls our JavaScript function. I know we haven't discussed functions yet - that's the next topic - but just remember that a function is like a mini program called by other programs. In this case it is defined at the top of the code.

The first few lines simply create some local variables and convert the form input strings to integers where needed. The bold section is the bit we are really interested in. It selects the appropriate action based on the shape value, notice, by the way, that the parentheses around shape are required. Each block of code within the case structure is not marked using curly braces, as you might expect, but is instead terminated by a break statement. The entire set of case statements for the switch is, however, bound together as a block by a single set of curly braces.

Finally, note the last condition is default which is simply a catch-all for anything not caught in the preceding Case statements. Try it above, it should work provided you fill in the length/breadth before picking a shape!

Why not see if you can extend the example to cover circles as well? Remember to add a new option to the HTML form drop-down as well as a new case to the switch.

VBScript Select Case

VBScript has a case construct too:

<script type="text/vbscript">
Dim shape, length, breadth, SQUARE, RECTANGLE, TRIANGLE
SQUARE = 0
RECTANGLE = 1
TRIANGLE = 2
shape  = CInt(InputBox("Square(0),Rectangle(1) or Triangle(2)?"))
length = CDbl(InputBox("Length?"))
breadth  = CDbl(InputBox("Breadth?"))
Select Case shape 
 Case SQUARE
   area = length * length
   MsgBox "Area = "  & area 
 Case RECTANGLE
   area = length * breadth
   MsgBox "Area = " & area
 Case TRIANGLE
   area = length * breadth / 2
   MsgBox "Area = " & area
 Case Else 
   MsgBox "Shape not recognized"
End Select
</script>

As with the JavaScript example the first few lines simply collect the data from the user and convert it into the right type. The bold Select section shows the VBScript case construct with each successive Case statement acting as a block terminator for the previous one. Finally there is a Case Else clause which, like the default in JavaScript catches anything not caught in the Cases above. As is the VBScript style, the whole thing gets closed of with an End select statement.

One other feature worth pointing out is the use of Symbolic Constants instead of numbers. That is the uppercase variables SQUARE, RECTANGLE and TRIANGLE are there simply to make the code easier to read. The uppercase names are simply a convention to indicate that they are constant values rather than conventional variables, but VBScript allows any variable name you like.

Python multi-selection

Python does not provide an explicit case construct but rather compromises by providing a slightly more compact if/else-if/else format:

menu = """
Pick a shape(1-3):
   1) Square
   2) Rectangle
   3) Triangle
"""
shape = int(input(menu))
if shape == 1:
   length = float(input("Length: "))
   print( "Area of square = ", length ** 2 )
elif shape == 2:
   length = float(input("Length: "))
   width = float(input("Width: "))
   print( "Area of rectangle = ", length * width )   
elif shape == 3:
   length = float(input("Length: "))
   width = float(input("Width: "))
   print( "Area of triangle = ", length * width/2 )   
else: 
   print( "Not a valid shape, try again" )

Note the use of elif and the fact that the indentation (all important in Python) does not change (unlike the nested if statement example). It's also worth pointing out that both this technique and the earlier nested if/else example are equally valid, the elif technique is just a little easier to read if there are many tests. The final condition is an else which catches anything not caught by the previous tests, just like the default in JavaScript and Case Else in VBScript.

VBScript also provides a slightly more cumbersome version of this technique with ElseIf...Then which is used in exactly the same way as the Python elif but is less commonly seen since Select Case is easier to use.

Breaking the Cycle

This section covers a specific use of branching that I really wanted to discuss back in the Loops topic but couldn't because we hadn't covered if statements at that point. So now we take a short reversion to the topic of loops and see how branching can solve a common looping problem.

There are times when you want to exit a loop before it finishes. To do this most languages provide a mechanism to break the loop execution. In Python this is the break keyword. It can be used in either a for or while loop. Typical uses are where you are searching a list for some value and once you find it you don't need to process any more. Another common case is when you find that your data is corrupted or you hit some kind of error condition (we talk about how to identify errors in a later topic).

One of the most common uses, especially in Python where it has become an accepted idiom (or recognised as a standard practice), is when reading input using a while loop. Meantime here is an example of using break to exit when we find the first zero value in a list of numbers:

  nums = [1,4,7,3,0,5,8]
  for num in nums:
     print( num )
     if num == 0:
        break  # exit the loop immediately
  print("We finished the loop")
  

You can see how we test for the exit condition in an if statement and then use break to jump out of the loop.

JavaScript also has a break keyword which is used in exactly the same way as in Python. VBScript uses the keywords Exit For or Exit Do to break out of its loops.

There is a close relative to break called continue. It is much less commonly used than break and its effect is to exit the body of the loop but, rather than ending the loop completely, it just jumps back to the start of the loop and commences the next iteration. While this can be useful if, for example, you only want to process certain kinds of data. But, you can achieve the same effect with an if condition within your block.

Python and JavaScript have the continue keyword but VBScript does not.

Putting it all together

So far many of our examples have been pretty abstract. To conclude let's take a look at an example that uses nearly everything we've learned about so far to introduce a common programming technique, namely displaying menus for controlling user input.

Here is the code, followed by a brief discussion:

menu = """
Pick a shape(1-3):
   1) Square
   2) Rectangle
   3) Triangle

   4) Quit
"""
shape = int(input(menu))
while shape != 4:
   if shape == 1:
      length = float(input("Length: "))
      print( "Area of square = ", length ** 2 )
   elif shape == 2:
      length = float(input("Length: "))
      width = float(input("Width: "))
      print( "Area of rectangle = ", length * width )   
   elif shape == 3:
      length = float(input("Length: "))
      width = float(input("Width: "))
      print( "Area of triangle = ", length * width / 2 )   
   else: 
      print( "Not a valid shape, try again" )
   shape = int(input(menu))

We've added just three lines (in bold) to the previous Python example but in so doing have significantly enhanced the usability of our program. By adding a 'Quit' option to the menu, plus a while loop we have provided the capability for the user to keep on calculating sizes of different shapes until she has all the information she needs. There is no need to rerun the program manually each time. The only other line we added was to repeat the input(menu) shape selection so that the user gets the chance to change the shape and, ultimately, to quit.

What the program does is create the illusion to the user that the program knows what they want to do and does it correctly, acting differently depending on what they input. In essence the user appears to be in control, whereas in fact, the programmer is in control since he has anticipated all the valid inputs and how the program will react. The intelligence on display is that of the programmer, not the machine - computers after all are stupid!

You see how easily we can extend our program just by adding a few lines and combining sequences (the blocks that calculate the area), loops (the while loop) and conditionals (the if/elif structure). Dijkstra's three building blocks of programming. Having covered all three you can, in theory, now go out and program anything, but there are a few more techniques we can learn to make things a bit easier, so don't rush off just yet.

DRY: Don't Repeat Yourself

There is one other feature of this program I'd like to pick up on. Notice that we had to repeat the input() line, once before the loop and once inside. Repeating identical code like that is a bad practice because if we ever need to change it we have to remember to change both lines - and that's error prone. There is a trick that we can use based on the break feature that we discussed in the loop topic. The trick involved making the while loop into an infinite loop, that is one which loops forever. Then we test for our exit condition and use break to leave it. It looks like this:

menu = """
Pick a shape(1-3):
   1) Square
   2) Rectangle
   3) Triangle

   4) Quit
"""
while True:
   shape = int(input(menu))
   if shape == 4: break
   
   if shape == 1:
      length = float(input("Length: "))
      print( "Area of square = ", length ** 2 )
   elif shape == 2:
      length = float(input("Length: "))
      width = float(input("Width: "))
      print( "Area of rectangle = ", length * width )   
   elif shape == 3:
      length = float(input("Length: "))
      width = float(input("Width: "))
      print( "Area of triangle = ", length * width / 2 )   
   else: 
      print( "Not a valid shape, try again" )

This maxim of minimizing repetition is given a name in programming circles: the DRY principle. For Don't Repeat Yourself!

Conditional Expressions

One form of branching that is very common is where we want to assign a different value to a variable depending on some condition. This is very easily done using a standard if/else condition, like so:

if someCondition:
   value = 'foo'
else:
   value = 'bar'

However, this is so common that some languages provide a shortcut that is called a conditional expression structure. In Python this looks like:

value = 'foo' if someCondition else 'bar'

This is identical to the longer form above. VBScript doesn't have such a structure but JavaScript does provide something similar using a slightly cryptic syntax:

<script type="text/javascript">
var someCondition = true;
var s;

s = (someCondition ? "foo" : "bar");
document.write(s);
</script>

Notice the strange syntax in the parentheses? Basically it does the same as the Python version but just uses a more concise set of symbols. Basically it says if the expression before the question mark is true then return the value following the question mark, otherwise return the value after the colon. Notice also that I used parentheses in this example. These aren't required but they often make it more obvious what is going on and I recommend them when using conditional expressions, even in Python.

These kinds of stylistic shortcuts can be convenient but many programmers find them a bit clumsy and prefer not to use them. My personal advice is to use them where it makes sense, usually in simple cases, but avoid them if it starts to make the code look overly complex.

Modifying collections from inside loops

We mentioned in the looping topic that modifying a collection from inside a loop was a difficult thing to do, but never got round to explaining how to do it! The reason is, we had to wait for branching to be explained first. So here is the solution:

If we need to modify the elements of a collection in place we can use a while loop to make the changes as we iterate over it. We can do this because in a while construct we have explicit control over the index, unlike the situation in a for loop where the index is automatically updated. Let's see how to delete all zeros from a list:

myList = [1,2,3,0,4,5,0]
index = 0
while index < len(myList):
   if myList[index] == 0:
      del(myList[index])
   else: 
      index += 1
print( myList )

The thing to note here is that we do not increment the index if we remove an item, we rely on the deletion moving everything up so that the old index value now points at the next item in the collection. We use an if/else branch to control when we increment the index. It's very easy to make a mistake doing this kind of thing so test your code carefully. There is another set of Python functions which are specifically designed for manipulating list contents and we look at them in the Functional Programming topic in the advanced section of the tutorial.

Things to Remember

Previous  Next