Control Structures

Download Report

Transcript Control Structures

Control Structures
Ranga Rodrigo
Control Structures in Brief
C++ or Java
Eiffel
if-else
if-elseif-else-end
case
inspect
for, while, do-while
from-until-loop-end
Structured Programming
Any structured program can be written using
sequence statements,
conditional statements, and
repetition.
Sequence
Conditional
Statements
Loops
Control Structures
They control the sequence of basic statements
that is executed.
They break a program up into relatively
independent pieces, each of which behaves in
a simple and predictable way: they introduce
structure into programs.
Eiffel tries to simplify the normal repertoire
control structures in some aspects.
With No Control Structures
Two mechanisms:
Jump or goto instructions.
Subroutine calls.
FORTRAN example:
10
20
X = 0
X = X + 1
A[X] = ...
IF (X.EQ.10) GOTO 20
GOTO 10
CONTINUE
Structured: No gotos
goto can create very complex programs:
spaghetti-like.
Edsgar Dijkstra: “goto statement … considered
harmful.”
Structured: replace the use of jumps by a small
set of simple and well-understood control
structures.
E.g., the loop above is replaced by a for
statement:
10
20
X = 0
X = X + 1
A[X] = ...
IF (X.EQ.10) GOTO 20
GOTO 10
CONTINUE
for (x = 0; x < 10; x++)
{
a[x] = ...
}
One Entry- and Exit-Point Rule
One commonly quoted rule of structured
programming was that each control structure
should have only one entry point and one exit
point.
The idea was that this would make it easy to
understand what a program is going to do next.
One Entry- and Exit-Point Rule
Eiffel enforces this rule consistently.
C++/Java do not:
break allows you to jump out of the middle of a
loop.
continue in effect jumps back to the beginning of
the current loop.
C and C++ have a goto statement.
Control Structures and Exceptions
One problem with structured programming is
that it can be awkward to deal with error
trapping and exceptional situations.
C++, Java, and Eiffel all have an exception
mechanism which allow control to be
transferred elsewhere in the program in certain
circumstances.
Sequencing
The default control structure is to perform
statements one after another, in the order in
which they are written: sequencing.
Many languages use semi-colons to separate
statements, but in Eiffel these are optional.
Conditional Statement: IF
if test then
...
elseif test then
...
else
...
end
The elseif and else clauses are optional.
Control enters an if statement at the top, and
leaves at the end.
Case or Switch: INSPECT
if option = 'c' then
counter.clear
elseif option = 'i' then
counter.increment
elseif option = 'p' then
counter.print
else
io.print_string("Invalid option")
end
Case or Switch: INSPECT
inspect exp
when a, b, c then
...
when x .. z then
...
else
...
end
exp must be of type INTEGER or CHARACTER. After when the
programmer can specify lists or subranges of values. The
else part of the instruction is optional.
Iteration: from-until-loop-end
from
initialization
until
exit condition
loop
...
end
Iteration
This loop will continue until the exit condition
becomes true.
This is the opposite behaviour from C++ or
Java while loops, which terminate when the
condition becomes false.
There is no loop statement in Eiffel with the test
of the exit condition at the end (No do-while
loop.)
There is no for statement.
Iteration
This loop will continue until the exit condition
becomes true.
This is the opposite behaviour from C++ or
Java while loops, which terminate when the
condition becomes false.
There is no loop statement in Eiffel with the test
of the exit condition at the end (No do-while
loop.)
There is no for statement.
for in Eiffel
from
i := 0
until
i = 10
loop
-- do stuff
i := i + 1
end
Iteration
The only way an Eiffel loop can finish is by the
exit condition becoming true.
Unlike C, C++ and Java there are no break or
continue statements.
This follows the structured programming
principle of making the flow of control easy to
follow.
Arguably, it makes the conditions of some loops
harder to write and read.
E.g., Locating a Value in an Array
find(v : INTEGER; a : ARRAY[INTEGER]) : INTEGER is
local
i : INTEGER
do
from
i := a.lower
found := false
until
found or i > a.upper
loop
if a.item(i) = v then
found := true
else
i := i + 1
end
end
Result := i
end
The debug Statement
debug
io.put_string("x = ")
io.put_integer(x)
end
debug("all")
io.put_string("y = ")
io.put_real(y)
end
Procedures
p (arg1 : Type ; ... ; argn : Type) is
require
-- precondition here
local
-- local entities declared here
do
-- compound statement here
ensure
-- postcondition here
end
Procedures
The only way of exiting from a routine body is
by reaching its end. Eiffel has no return
statement.
Formal parameters (the args) cannot be
assigned to in the body of a routine.
Parameters are initialized by assignment .
Procedure calls are written using p(x, y)
notation. If there are no parameters, however,
the brackets are omitted.
Functions
f (a1 : T1 ; ... ; an : Tn) : T is
require
-- precondition
local
-- local entities declared here
do
-- statement, assignment to 'Result'
Result := return value
-- more statements
ensure
-- postcondition
end
Fucntions
In addition to the points made about routines:
Result is an implicitly declared local variable of the
return type of the function.
The value held in Result when the function ends is
the value returned by the function
When a function is called, you must do something
with the returned value.
Control Structures and DBC
Pre- and post-conditions state properties that
should be true at the beginning and end of a
routine.
They are not called by client code. They are not
usually specified as formally as routines.
However, it can be useful to annotate code with
expected properties. As with DBC, this can be a
good way of catching errors in program
development.
Assertions
The check statement can be used to add runtime checks at any point in a program.
For example, after completion of the loop in the
find function, the value of i should beat most
one more than the upper bound of the array:
check
a.lower <= i and then i <= a.upper + 1
end
Specifying Loops: Variants and
Invariants
Loop design can be difficult: the exit condition
must be correct, and the loop must execute the
correct number of times.
Eiffel supports the use of loop variants and loop
invariants (not to be confused with class
invariants) to specify the behaviour of loops.
The invariant is an expression that must be true
every time the loop restarts.
The variant is an integer expression that must
get less every time the loop repeats. This
ensures that it will terminate.
make is
local
v : INTEGER
a : ARRAY[INTEGER]
i : INTEGER
found : BOOLEAN
do
create a.make(1,10)
from
i := 1
found := false
invariant
-- v not in the array slice [1..i)
variant
10 - i
CONTD.
until
found or i > 10
loop
if a[i] = v then
found := true
else
i := i + 1
end
end
io.put_integer(i)
end
CONTD.