Part 4: Control Constructs

Control Constructs

In the last section, we saw how to indicate to the computer the various types of entities we have, using the notion of data types and associated operations. We had ignored the issue of how to define new operations and how to manipulate these entities. In this section, we take up this issue. We did see some basic manipulation, when we discussed the assignment operator and arithmetic expressions. So we know how to tell the machine that HRA is 30% of the basic pay and that area of a rectangle is the product of its length and breadth (area = breadth x length).

We will start our discussion with input/output. We will not spend much time on this here, since the syntax and details of input/output vary widely across languages. Therefore, we restrict to why we need it and the basic primitives for input/output.

As we mentioned earlier, a program normally solves a problem - it could be solving a quadratic equation, or reserving a flight ticket or searching for some information on the web. In solving a problem, we have two types of data we use. Consider the flight reservation problem. The list of flights, the charges for each flight, taxes payable, etc are the same for each booking. These can be given in the program itself - as we did for b and c in our first program. Remember that, for that program, we had to change the program to solve a different equation. It would be better, if the program could ask you for value of a, b and c, when it starts running. This is where runtime input-output comes useful. In our flight reservation program, the corresponding data are the passenger name, the sector he/she wants to fly, the time of flight, etc. These will change from booking to booking, and is best given at the time of running the program.

We could modify the program (for solving roots of quadratic equation) as:

input a
input b
input c

instead of the 'a = ', 'b = ' and 'c = ' lines. The effect is similar. When the program is run, the program will expect you to give the values of a, b and c in that order.

\$a.out
12
4
3
3 1

Here 12, 4 and 3 are the values of a, b and c; and 3 and 1 are the roots output by the program.

Usually most languages provide simple primitives to read numbers, floating point numbers, characters and strings. Sequences like arrays and complex types need special functions to read in their values. We will shortly see how to read sequences. For complex types, say a person type with fields name and age, one can define reading a person as reading a name (which is a character string), and then reading age which is a number. We will wrap these as a function so that henceforth we can just say

input x

and if x is of type person, it will read and initiatise the various fields correctly. We may also write this as x.input() to indicate invocation of the input method on the data type of which x is an instance. The programming language and compiler is smart enough to figure out the type of x and process the inputs correctly. As mentioned earlier, the exact primitives vary from language to language.

Just like input, we need to communicate results of our problem solving to the user. We may want the final result, the intermediate results, status messages, etc to be shown to the user. Again the actual syntax can vary heavily across languages. We will assume:

print x or
x.print()

as the notation. Recall the 'print r1, r2' in our first program. We write

print "the equation has no roots"

which will output the string as it is. Alternatively, we can write the same thing as:

msg1 = "the equation has no roots"
print msg1

When outputing, we sometimes need some layout conventions. For example, all money variables should be printed with exactly 2 decimal places; when there are multiple such values, print them on separate lines with the decimal points aligning vertically to aid readability; and so on. All languages provide formatting directives for such purposes. For example, there is usually a way to say when printing a number, to use n character spaces for the integer part and m for the decimal part. So, with n=5 and m = 2, 13.902 will become ' 13.90', and 3.5 will become ' 3.50'. We leave input-output here, for now.

Conditional Statements

When discussing quadratic equation, we faced a situation that if the descriminant is negative, the program wont work. We bravely made the assumption that such equations will not be given as input and escaped! This is not a good strategy. It is better that the program checks for this condition, and alert the user. So, before computing the roots, we would like to do something like this:

if descr < 0 then print "error: roots are not real" and terminate the program; else compute roots as before.

Conditional statements in programming languages provide essentially this ability. In general, they have the format:

if <condition>
<statement-set1>
else <statement-set2>

The word "then" is rarely used, since at the end of the condition, the statement block is assumed to start. The condition is, usually assumed to be brackets to reduce confusion. The 'else' part is usually optional. If 'else' is omitted and the condition is false, the entire 'if' statement has no effect. (This is not true, if the condition expression can create side effects - but we ignore this possibility here). Some languages provide an explicit terminator 'fi' (for 'if' in reverse) or 'end' to indicate end of the if statement.

The interpretation is fairly obvious. First, evaluate the condition. If it is true, execute the statement set1. Otherwise, if there is an else part, evaluate the set 2. If there is no else part (ie, the set 2 does not exist), do nothing further. Move to the next statement following this.

Unlike the else part, the then part is not optional. If you have nothing to do when the condition is true, and want to perform something otherwise, you can either invert the condition (so that the then part now contains what you want to do, and the else can be left out), or include a 'do nothing' statement in the then part. Most languages provide the equivalent of a 'do nothing' - it may be called 'skip', an empty statement and so on. It is 'skip()' in PHP. So, you can write

if (descr > 0)
skip();
else print "error"

is same as

if (descr <= 0)
print "error"

The statements inside the then and else can be any statement, including another if statement. Thus, you can nest statements. For example, you can use this to implement a 3-way or 4-way decisions, using the 2-way if-statement. You want to assign variable v to 1, if the age is less than 20, 2, if the age is more than 20, but less than 40, and 3, otherwise. You can write this as:

if (age <= 20)
v = 1
if (age > 20) and (age <= 40)
v = 2
if (age > 40)
v = 3

You have used three if-statements here to implement. If the first condition failed, you dont need to check if age > 20, it will have to be. Similarly, if the first 2 if-statements did not succeed, then the third condition has to be true. Using this insight, we can write the same thing as

if (age <= 20)
v = 1
else if (age <= 40)
v = 2
else v = 3

Instead of four conditions, we have only 2, and is more compact. However, be careful when nesting if statements. Look at this:

if (condA)
if (condB)
set-1
else set-2

When is set 2 executed - if condA is false, or if condB is false? "else set-2" is associated with the inner if-statement in most languages. Dont get fooled by the indentation. In most languages, indentation is only for the human programmer; the language ignores it. Languages provide a grouping construct to handle such situations. For example, in C and Java, you would use '{' and '}' to group statements. In PHP, the indentation is important to the language, and hence that would take care. Either way, make sure your intentions are clearly communicated to the computer. In PHP, the above statement associates set-2 to when condA is false.

This is particularly important, when you have more complex nesting of statements - as you will see when we discuss loops.

Before we leave conditionals, let us meet a friend of 'if-statement'.

There is a common usage of multi-way branching as follows. You may be familiar with the message you get when calling customer service numbers. It would be something like this: "press 1 if you want to reserve a ticket, press 2 if you want to cancel ticket, press 3 to know about current schedule, press 4 to register a complaint, ….". If you were to write a program to write this interaction, it would look something like this. Assume cmd is the variable holding the digit the user pressed:

if (cmd == 1) reserve()
else if (cmd == 2) cancel()
else if (cmd == 3) display_sched()
else if (cmd == 4) complaint()
else print "invalid option"

You are actually making a multiway branch to different parts of your program implementing different functions. Most of today's languages provide a simpler way to implement this kind of branching, where choice is based on different values of a single variable. This is the 'switch' statement. With this, we can write the above as:

switch (cmd)
1 : reserve(); break;
2 : cancel(); break;
3 : display_sched(); break;
4 : complaint(); break;
default: print "invalid option"
end

This is a lot cleaner and easier to maintain. Adding another option is pretty easy here. There is more to switch statement, though. Study the construct from your language manual before using, since there are significant variations in the details among languages. For example, many languages assume a 'fall through' behaviour in the action statements. So that if 'cmd' is 1, it will execute reserve(), and then will go on to execute cancel(), display_sched(), etc normally. In these languages, you need to put an explicit 'break' statement to prevent this from happening. This is most of the time the desired behaviour. If you want a fall through, omit the break statement. In other languages, the action statements are assumed to end, when the next switch value is seen.

Since switch is a sequence of branches, there must be a way to end the sequence. Many languages require an "end" or some such construct to signal the end of the switch statement. PHP uses indentation here also. If the next statement is at the same or lower indentation than the 'swtich' line, the switch is assumed to have ended.

We now move to the most important programming construct, the loops.

page revision: 4, last edited: 17 Oct 2009 06:41