Statement Level Flow of Control Selection Structures Copyright © by Curt Hill
Control Structures In the beginning was FORTRAN FORTRAN reflected the machine that it was designed on: IBM 704 It had five control structures: –Unconditional GOTO –Logical If –Arithmetic If –Do loop –Computed GOTO We should be critical but they just did not know any better
1 and 2 of the Five Unconditional GOTO GOTO 5 –FORTRAN was column oriented and statement labels were numbers –These resided in columns 1-5 Logical if if (a.gt.e) GOTO 12 –It could only have one statement following it and not every statement either –Usually an assignment or goto Copyright © by Curt Hill
3 and 4 of the Five Arithmetic if if(a)10,20,30 –A must be an integer –Then we branched to one of the three labels based on A negative, zero or positive Do loop do 15,i=1,10,2 –Similar to the counting for of many languages –First number was the last statement of the loop –There was an assignment, limit and increment –The do was actually a trailing decision loop Copyright © by Curt Hill
Last of the Five Computed GOTO goto (10,15,20,5,30), i –Precursor to a case –If i = 1 goto first label –If i = 2 goto second label etc –All of these translated directly into 704 machine language Copyright © by Curt Hill
Is that the best we can do? In those days we did not know what would make for good programming practices, but in the early sixties the goto wars began Those who only knew Assembly or FORTRAN or COBOL got carried away and used gotos to make some rather beastly execution flows –These were motivated by efficiency –Machines were quite expensive and people still relatively inexpensive (>$5/CPU second) Copyright © by Curt Hill
What’s wrong with this? Copyright © by Curt Hill IF (A.GT.B) GOTO IF (A.EQ.C) GOTO 70 A = B * C 20IF(C.EQ.0) GOTO 90 A = A * 2 IF (R.GT.2) GOTO 40 C = A+B*2-C IF(B.GT.C) GOTO 50 READ(*,5)R,C 40B = B + R - C GOTO CONTINUE... 90CONTINUE
The GOTO Wars The Structured Programming types coined the term spaghetti code to describe how these programs used flow of control –These were led by Dijkstra and others The war was fought in the Journals –Titles: goto considered harmful Copyright © by Curt Hill
Crushing Victory In 1966 Bohm and Jacoppini proved that any program could be written with just three structures: sequence, if and while –This cut the theoretical ground out from under the GOTO proponents –The war did last several more years Copyright © by Curt Hill
Last Shot The last shot was in 1974 when D.E. Knuth published Structured Programming with GOTOs –Among other things it said that good programmers used the GOTO in a way that was reasonable before there were languages that supported it –This was almost a face saving article on behalf of the GOTO crowd and marked the end of the war Copyright © by Curt Hill
Preprocessors By the late sixties there were a number of preprocessors for FORTRAN that would make real control structures and translate them into if-goto structures –These did what the compiler did in assembly language: convert nice structures into what the machine has However the languages that supported structured programming rapidly supplanted FORTRAN as the king of the languages Copyright © by Curt Hill
Three or More? Just because you can program with just the three does not mean that we should only have the three –Writability is aided by more –Structured programming does demand that each control structure be single entry and single exit –The worst control structure ever created was a multiple entrance, multiple exit loop –However, multiple exit loops are not a problem Copyright © by Curt Hill
Compound statements FORTRAN’s flow of control would not have been near the problem if the IF could have had multiple statements Forcing a GOTO after an IF made it seem like the GOTO was the correct statement –Recall Sapir Whorf hypothesis ALGOL 60 introduced the compound statement, which was a BEGIN - END similar to what we see in its descendants Pascal and Ada Copyright © by Curt Hill
Compound Statements The ALGOL 60 compound statement was called a block and was stronger than the compound statement in Pascal or C –It allowed declaration of variables and scope C++ and Java also allow this more general block in that you can declare variables but not always new functions Copyright © by Curt Hill
Selection statements The design issues: –How many ways? 1, 2, many –What controls the selection? Form and type? –What restrictions on what statement(s) are controlled? –Nesting of selections? Copyright © by Curt Hill
One way The FORTRAN IF was one way It had a one statement then It had no else, which if needed was constructed using GOTOs A boolean controlled it, but the statement was only executed on true It also used negative logic –The if said when to GOTO which bypassed the next statements rather than the condition to execute them –Thus the next statement was an else Copyright © by Curt Hill
Two Way ALGOL 60 had the one way and also had two way It introduced the THEN and ELSE as well as the block Most languages have followed this pattern since then FORTRAN 66 did not but 77 did Copyright © by Curt Hill
Nesting The two way if makes nesting a problem If an if is in an if who gets the else? The Pascal solution is to give the else to the first unmatched if –Use a compound statement to override that approach –This takes a disambiguation rule, since the grammar is actually ambiguous on this point Copyright © by Curt Hill
Language Choices The ALGOL 60 solution is to disallow an if as the then statement –Especially since it introduced blocks –C and C++ follow Pascal Perl forces all thens and elses to be compound statements Ada has different endings for different things –Thus an IF always starts an implied compound statement Python uses indentation Copyright © by Curt Hill
Python Example Copyright © by Curt Hill if sum == 0 : if count == 0 : result = 0 else : result = 1
Syntactic boundaries Where does the condition end and the executable statement begin? In FORTRAN I you could only compare a variable to a variable or constant –There were ANDs/ORs added later –Thus it was easy to tell what came next In most later languages an expression may be on both sides of a the relational and there are complications added by ANDs and Ors Copyright © by Curt Hill
Boundaries Pascal has a THEN to terminate its if condition C/C++/Java enclose the condition in parentheses so do not need a Then All of these only allow a single statement for the then or else, so the compound statement is heavily used When an END or } is encountered it is not obvious what started it Copyright © by Curt Hill
Ada and Boundaries Ada uses another approach –It uses end if to terminate an if so does not need the compound statement –The then part starts with THEN and ends with ELSE or END IF –This also straightens out the nesting issues Modula 2 closes every control structure with end, which is somewhat similar to Ada but less readable Copyright © by Curt Hill
Need for Multiways Very often we run into situations like the following –Series of Ifs –The then part does something –The else part is another IF –The comparison condition is always the same: variable = constant –All ifs have the same variable, but different constants Copyright © by Curt Hill
Multiway Selectors The design issues: –About the same as Ifs –What controls the selection? Form and type? –What restrictions on what statement(s) are controlled? Single, sequences or compound statements? –How to encapsulate the statement? –May just a single segment be executed? –What to do about unrepresented values? Copyright © by Curt Hill
FORTRAN The FORTRAN arithmetic if and computed goto are the first Computed GOTO goto (10,15,20,5,30), i –If i = 1 goto first label –If i = 2 goto second label etc Arithmetic if if(a)10,20,30 –Then we branched to one of the three labels based on A negative, zero or positive Copyright © by Curt Hill
FORTRAN Problems These are much more insidious than modern cases because the target labels can be anywhere in the program – before or after Moreover these labels may be accessed by other GOTOs –This violates single entry principle These are strongly based on IBM 704 Copyright © by Curt Hill
A Modern Case? ALGOL-W was the first with a near modern case The statements are numbered by occurrence without a label The case selector must be a positive integer Each statement may be a compound statement Copyright © by Curt Hill
ALGOL W Case Copyright © by Curt Hill case j of begin x:=5; // Chosen by j=1 begin // Chosen by j=2 r := 2; s := x*r; end; z := 0;// Chosen by j=3 end
Pascal generalizes this Case labels explicitly identify the value The label and the selector must match and be ordinal type The labels can be in logical not numeric order This allows negative and non- contiguous values as well Subranges of values and lists of values are allowed No option for an ELSE clause though most dialects have a non-standard way to do it Copyright © by Curt Hill
Pascal Case Copyright © by Curt Hill case color of blue: x := 5; red,green: begin r := 2; j := 5; end;
C Family The C, C++, Java switch is primitive –The lack of a break allows multiple segments to be executed –The case makes for difficult ranges –However the default is good The Ada case follows Pascal in function (slightly different form) but has an others clause FORTRAN 90 is similar to Ada Copyright © by Curt Hill
C Example Copyright © by Curt Hill switch (i) { case 2: r = 4; j = 5; // allows drop into case 5: x = 7; break; default: x = 0; }
Ruby Example Copyright © by Curt Hill leap = case when year % 400 == 0 then true when year % 100 == 0 then false else year % 4 == 0 end
Implementation Conversion into nested if then else Table of addresses –Search it –Hash into it –Jump into it This only works for contiguous values Copyright © by Curt Hill
Multiple nested ifs Recall that the switch or case statement is not very general –Series of Ifs –The then part does something –The else part is another IF –The comparison condition is always the same: variable = constant –All ifs have the same variable, but different constants In some sense the case generalizes the if from Boolean to other ordinal values Copyright © by Curt Hill
Is that good enough? There are many more situations where this kind of structure does not work but we still have the if then else if then else if form –But the form of the condition is different How can this be handled? The default is that each if should have its own complete structure –Pascal, C family –This can be error prone when it is deeply nested Copyright © by Curt Hill
Ada Does Better Ada allows an elsif which condenses the amount of writing for deeply nested if then elses It also allows fewer end items Notice that the difference between a case and nested if is that the case only examines one expression to determine the selection Copyright © by Curt Hill
Ada Example Copyright © by Curt Hill -- Increment NumPos/Neg/Zero IF X > 0 THEN NumPos := NumPos + 1; ELSIF X < 0 THEN NumNeg := NumNeg + 1; ELSE -- X is zero NumZero := NumZero + 1; END IF;
Now What? This concludes selection statements –Except guarded statements Next we need to consider looping Copyright © by Curt Hill