11 - Loops#
Iterative Statements#
The repeated execution of a statement or compound statement is accomplished either by iteration or recursion.
General design issues for iteration control statements:
How is iteration controlled?
Where is the control mechanism in the loop?
Counter-Controlled Loops#
A counting iterative statement has a loop variable and a means of specifying the initial, terminal, and stepsize variables.
Design issues:
What are the type and scope of the loop variable?
Should it be legal for the loop variable or loop parameters to be changed in the loop body, and if so, does the change affect loop control?
Should the loop parameters be evaluated only once, or once for every iteration?
What is the value of the loop variable after loop termination?
In C-based languages:
for ([expr_1]; [expr_2]; [expr_3]) statement
The expressions can be whole statements, or even statement sequences, with the statements separated by commas
The value of a multiple-statement expression is the value of the last statement in the expression
If the second expression is absent, it is an infinite loop
Design choices
There is no explicit loop variable
Everything can be changed in the loop
The first expression is evaluated once, but the other two are evaluated with each iteration
It is legal to branch into the body of a for loop in C
C++ differs from C in two ways:
The control expression can also be Boolean
The initial expression can include variable definitions (scope is from the definition to the end of the loop body)
Java and C# differ from C++ in that the control expression must be Boolean.
In Python:
for loop_variable in object:
# loop body
[else:
# else clause
]
The
object
in Python is often a range, which is either a list or a call to therange
functionThe loop variable takes on the values specified in the given range, one for each iteration
At loop termination, the loop variable has the last value that was assigned to it
The optional
else
clause is executed if the loop terminates normally (nobreak
)
In F#:
let rec forLoop loopBody reps =
if reps <= 0 then ()
else
loopBody()
forLoop loopBody, (reps - 1)
Because counters require variables, and functional languages do not have variables, counter-controlled loops must be simulated with recursive functions
The example above defines the recursive function
forLoop
with the parametersloopBody
(a function that defines the loop’s body) andreps
(the number of repitions)()
means do nothing and returns nothing
Logically-Controlled Loops#
In logically-controlled loops, repetition control is based on a Boolean expression.
Design issues:
Pretest or posttest?
Are both logically-controlled loops and counter-controlled loops needed?
C and C++ both have pretest and posttest forms, in which the control expression can be arithmetic:
while (control_expr)
loop body;
do
loop body
while (control_expr)
In both C and C++, it is legal to branch into the body of a logically-controlled loop
Java is like C and C++, except the control expression must be Boolean (and the body can only entered at the beginning, since Java has no goto
).
In F#:
let rec whileLoop test body =
if test() then
body()
whileLoop test body
else ()
As with counter-controlled loops, logically-controlled loops can be simulated with recursive functions
This defines the recursive function
whileLoop
with parameterstest
andbody
User-Located Loop Control Mechanisms#
Sometimes it is convenient for the programmers to decide a location for loop control (other than the top or bottom of the loop).
This is a simple design issue for single loops (e.g. break
), but nested loops must consider the following design issues:
Should the conditional break be part of the exit?
Should control be transferable out of more than one loop?
C, C++, Python, Ruby, and C# have unconditional unlabeled exits (break
).
Java and Perl have unconditional labeled exits (break
in Java, last
in Perl).
C, C++, and Python have an unlabeled control statement continue
that skips the remainder of the current iteration, but does not exit the loop.
Java and Perl have labeled versions of continue
.
Iteration Based on Data Structures#
The number of elements in a data structure controls loop iteration
Control mechanism is a call to an iterator function that returns the next element in some chosen order, if there is one; else loop is terminated.
C’s
for
can be used to build a user-defined iterator:
for (p=root; p==NULL; traverse(p)) {
...
}
In PHP:
current
points at one element of the arraynext
movescurrent
to the next elementreset
movescurrent
to the first element
Java 5.0 uses for
, although it is called foreach.
This works for arrays and classes that implement the
Iterable
interface (e.g.ArrayList
):
for (String myElement : myList) { ... }
C# and F# (and the other .NET languages) have generic library classes, like Java 5.0 (for arrays, lists, stacks, and queues). These can be iterated over with the foreach
statement. User-defined collections can also implement the IEnumerator
interface and also use foreach
.
List<String> names = new List<String>();
names.add("Bob");
names.add("Carol");
names.add("Ted");
foreach (Strings name in names)
Console.WriteLine("Name: {0}", name);
Ruby blocks are sequences of code, delimited by either braces or do
and end
Blocks can be used with methods to create iterators
Predefined iterator methods (
times
,each
,upto
):3.times {puts "Hey!"} list.each {|value| puts value}
list
is an array,value
is a block parameter
1.upto(5) {|x| print x, " "}
Guarded Commands#
Guarded commands were designed by Djikstra. Their purpose is to support a new programming methodology that supports verification (correctness) during the development. The basic idea is that if the order of evaluation is not important, the program should not specify one.
General form:
if <Boolean expr> -> <statement>
[] <Boolean expr> -> <statement>
...
[] <Boolean expr> -> <statement>
fi
Semantics: when construct is reached:
Evaluate all Boolean expressions
If more than one are true, choose one non-deterministically
If none are true, it is a runtime error
Selection guarded form:
if x>=y -> max := x
[] y>=x -> max := y
fi
Loop guarded command:
do <Boolean> -> <statement>
[] <Boolean> -> <statement>
...
[] <Boolean> -> <statement>
od
Semantics: for each iteration,
Evaluate all Boolean expressions
If more than one are true, choose one non-deterministically; then start loop again
If none are true, exit loop
Example#
Given four integer variables q1
, q2
, q3
, and q4
, rearrange the values of the four so that q1
\(\leq\) q2
\(\leq\) q3
\(\leq\) q4
:
do q1 > q2 -> temp := q1; q1 := q2; q2 := temp;
[] q2 > q3 -> temp := q2; q2 := q3; q3 := temp;
[] q3 > q4 -> temp := q3; q3 := q4; q4 := temp;
od