3.4. Choice Of Control Structures

Though not recognized as that by all programmers, the flow control structures themselves are first class indicators of the code's workings. We consider three important cases here.

  1. while vs. for,

  2. if vs. select, and

  3. strict block structure vs. premature return.

3.4.1. while/for

Expressed in words a for loop tells us:

Whereas the while loop says:

Corollary: The termination condition of a while must be influenced in the loop's body.

Compare the next two code snippets, the first one calculating the average value of a vector of numbers, the second searching zeroes of a given function.


values = [1.0, 2.0, 3.0, 4.0, 5.0];
average = 0.0;
n = size(values, 'c');             // line 3
for i = 1:n
    average = average + values(i);
end;
average = average / n

From 7nbsp;3 on, we know the number of iterations, n, and we know that nothing will change that. Thus a for loop is adequate.


deff('[y, dy] = fun(x)', ..
     'y  = -0.5 + 1.0/(1.0 + x^2), ..
      dy = -2.0 * x / (y + 0.5)^2');

x0 = 0.76;
[y, dy] = fun(x0);
while abs(y) > sqrt(%eps)
    x = y/dy - x0;
    x0 = x;
    [y, dy] = fun(x);
end;
x

Assuming that the function fun, and the start guess x0 are supplied by the user, we do not know how many loops it will take for Newton's algorithm to converge, if it does converge at all. (In the example it does.) Here, the while-loop expresses this lack of a-priori knowledge.

3.4.2. if/select

The relationship between if and select bears similarity to while and for, respectively. In a select clause the different cases are known – and spelled out explicitely – before the thread of control enters the construct. There is a one to one relationship between the states of the selecting expression and the case branch taken. The else branch in a select works exactly as the else in an if.


function f = fibonacci(n)
// return n-th Fibonacci number

select n
case 0 then
    f = 1
case 1 then
    f = 1
else
    f = fibonacci(n - 1) + fibonacci(n - 2)
end

The selecting expression is not restricted to scalars, vectors for example work too:


function s = shape4(m)
// classify a 2x2 matrix according to its shape

select abs(m) <= %eps
case [%t %t; ..
      %t %t] then
    s = 'empty'
case [%t %f; ..
      %f %t] then
    s = 'diagonal'
case [%f %f; ..
      %t %f] then
    s = 'upper triangular'
case [%t %t; ..
      %f %t] then
    s = 'lower triangular'
case [%f %f; ..
      %f %f] then
    s = dense'
else
    s = 'general'
end

An if clause is more flexible than a select clause, but at the price of being less expressive. Whenever a whole range of values has to be covered the if clause is the only way to go, as is demonstrated by Example 3-2.

Example 3-2. Function mysign


function y = mysign(x)
// re-write of the sign-function, taking
// floating-point precision into account

if abs(x) < %eps
    y = 0.0
elseif x >= %eps
    y = 1.0
else
    y = -1.0
end
   

3.4.3. Strict Block Structure/Early Return

The paradigm of structured programming is: "Every block has one and only one entry point." That is it! Nothing is said about the number of exit points. The purists often misinterpret the paradigm, demanding a single exit point, too. We prefer our freedom, and choose whatever we find adequate to the problem.

Here are two different implementations of an algorithm calculating the factorial of a given integral number.


function y = fact_block(x)
// faculty of x; block-structured version

select x
case 0 then
    y = 1
case 1 then
    y = 1
else
    y = x * fact(x - 1)
end

The two special cases 0, and 1 are tested separately, and the general case is handled in the else branch.


function y = fact_early_ret(x)
// faculty of x; early-return version

if x >= 0 & x <= 1 then
    y = 1
    return
end

y = x * fact(x - 1)

This version immediately returns after having treated the special cases, leaving the general case to the "rest" of the function. In this very short function the advantages of the early return are not striking, however they are if many special cases are to be handled. The "rest" of the function can then concentrate on the core of the problem without being obscured by deeply nested conditionals.