Control statements in imperative languages mirror the instruction-set hardware
// unconditional branches in C: (see code) j = 0; while (j < 3) { if (array[j] < 0) goto out_of_bounds; if (array[j] == 99) break; // breaks to first line after loop if (array[j] > 1) { j++; continue; // takes you to the top of the loop } } printf("break got me here\n"); cleanup(); out_of_bounds: printf("value %d got me here\n",array[j]);
for (i = 0; i < SIZE; i++) { if (num[i] <= 1.00) continue; // skip values <= 1.00 printf("value = %.2f\n", num[i]); }
for (i = 0; i < SIZE; i++) { if (num[i] <= 1.00) break; // exit loop completely for values <= 1.00 printf("value = %.2f\n", num[i]); }
! Example of spaghetti code in Fortran GOTO 10 ! jump forward 23 CONTINUE i = i - 1 IF (i .eq. 0) GOTO 99 10 PRINT "I Loop" 69 j = j - 1 ! loop print "J Loop" IF (j .ne. 0) GOTO 69 GOTO 23 ! jump back 099 CONTINUE
// the same code without gotos is cleaner do { print "I Loop" while (j>0) { print "J Loop" j-- } i-- } while (i > 0)
// try converting this into a loop without GOTOs or unconditional jumps L1: if (cond1) then goto L2 statement1; if (cond2) then goto L2 statement2; goto L1; L2: statement3;
If the last thing a function does before the return is call itself, the function is tail recursive.
// tail recursive - all the work is done on the way *up* the stack int sum = 0; void foo (int i, int list[]) { if (i == size) return; sum += list[i++]; foo (i, list); // last thing done is the recursive call } // NOT tail recursive - all the work is done on the way *down* while // popping the call frames int fac (int n) { if (n == 0) return 1 else return n * fac(n-1); // last operation is mult }
// tail recursive function void stuff (int n) { print n; if (n>0) stuff (n-1); } // converted into an equivalent loop while (n > 0) { print n; n--; }
void treeprint(Node * t){ if (t != null) { treeprint(t->left); print(t); treeprint(t->right); } }
First replace the tail recursive call with a goto:
void treeprint(Node * t){ L: if (t != null) { treeprint(t->left); print(t); t = t->right; <= normally done in the recursive call goto L; } }
The remaining recursive call can then be eliminated with a stack:
void treeprint(Node * t){ Stack s; <= holds pointers L1: while ( t != null ) { s.push(t); p = t->left; goto L1; L2: s.pop(t); print(t->value); t = t->right; } // end while if (!s.empty()) goto L2; } Example 6c.
All selection statements have a condition:
if (!EOF) read(ch); // executed when EOF is falseOne-Way Selection Statements
if (condition) statement(s); else statement(s);The dangling else problem:
if (sum == 0) if (count == 0) result = 0; else result = 1; // which 'if' gets the 'else'?
In Perl all then/else clauses are compound (solves dangling else)
To force alternative semantics use compound statements:
if (sum == 0) { if (count == 0) result = 0; } else result = 1;
Multiple-Way Selection Statements
switch (k) { // must be integral type case 2: Console.Write("\nm is 1 or 2\n", k); j = 2*k-1; break; //explicit break is required - no fall through case 5: Console.Write("\nm is 3 or 5\n", k); j = 3*k+1; break; case 4: Console.Write("\nm is 4\n", k); j = 4*k-1; break; case 1: // no fall through allowed in C# break; default: // supported but not required Console.Write ("\neverything else, m =%d\n", k); j = k-2; break; }
// syntax of C's switch statement switch (expression) { case const_expr_1: stmt_1; ... case const_expr_n: stmt_n; [default: stmt_n+1] }
Ada's "No Fall Through" is more reliable than C - once stmt_seq is completed, control is passed out
case expression is when choice list => stmt_sequence; ... when choice list => stmt_sequence; when others => stmt_sequence;] end case; next_stmt; // control passed here
Multiple-Way Selection with elsif
Unlike C, some languages include an explicit keyword for "else if" such as elsif or elif.
In Python:if x < 0: x = 0 print 'Negative changed to zero' elif x == 0: print 'Zero' elif x == 1: print 'Single'
if ... then ... elsif ... then ... elsif ... then ... else ... end if
if (num < 1.0) { print "1"; } elsif ( num < 2.0) { print "2"; } elsif ( num < 3.0) { print "3"; }
General design issues for iteration control statements:
#1 How is iteration controlled?
#2 Where is the control mechanism in the loop?
Design Issues:
Example, FORTRAN 90:
DO label var = start, finish [, stepsize]
1. Loop variable must be INTEGER type
2. Loop variable always has a last value
3. The loop variable cannot be changed in the loop
4. Loop parameters are evaluated only once and can be changed
after evaluation w/o affecting loop execution
5. Stepwize can be any value but zero
6. Parameters can be expressions
Example, Pascal:
for variable := initial (to|downto) final do statement 1. Loop variable must be an ordinal type of usual scope 2. After normal termination, loop variable is undefined 3. The loop variable cannot be changed in the loop 4. The loop parameters can be changed, but they are evaluated just once, so it does not affect loop controlExample, Ada:
for var in [reverse] discrete_range loop ... end loop 1. A discrete range is a sub-range of an integer or enumeration type 2. Scope of the loop variable is the range of the loop 3. Loop variable is implicitly undeclared after loop terminationExample: C's for loop is LISP-like
for ([expr_1] ; [expr_2] ; [expr_3]) statement which is equivalent to: expr_1; while ( expr_2 ) { statement expr_3; }
Java and C# force the exclusive use of Boolean expressions in control expressions.
upside is security: while (i = 1) // prevents this error since 'i' is INT type downside is a lack of flexibility: int num = 5; // you want num of type int to control while while (num){ // exit loop when num is 0 x / num; // a divide by zero error will never occur num--; }
while (ctrl_expr) // pre-test do loop body do loop body while (ctrl_expr) // post-test
for (p=root; p==NULL; traverse(p)) { . . . }
# Perl foreach(@words) { $word = $_; $word =~ tr/A-Z/a-z/; print 'word: ', $_, "\n"; }
Perl's while (<FILEHANDLE>) iterates on the lines of a file.// C# Strings[ ] = strList = {.Bob., .Carol., .Ted.}; foreach (Strings name in strList) Console.WriteLine (.Name: {0}., name);
open(WORDS, $filename); while(<WORDS>) { . . . } close(WORDS);
if <Boolean exp> -> <statement> do this [ ] <Boolean exp> -> <statement> OR do this ... [ ] <Boolean exp> -> <statement> OR do this fi
LOOP Guarded Command:
do <Boolean> -> <statement> [ ] <Boolean> -> <statement> ... [ ] <Boolean> -> <statement> od
if a >= b then print "More or equal"; else print "Less"; Guarded: if a >= b => print "More or equal" [ ] a < b => print "Less" fi
if a >= b -> print "More or equal" a <= b -> print "Less or equal" fi
When a = b, the result of command can be "More or equal" or "Less or equal".
Guarded commands are a means for controlling asynchronous message passing - allows all requestors an equal but nondeterministic chance of communicating ( see Ada code )
Ada has concurrency built-in. A task is the basic unit of concurrency. Concurrent hello world
with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random; procedure Concurrent_Hello is task type Writer (Message : access String); task body Writer is Seed : Generator; begin Reset (Seed); delay Duration (Random (Seed)); Put_Line (Message.all); end Writer; S1 : aliased String := "Enjoy"; S2 : aliased String := "Rosetta"; S3 : aliased String := "Code"; T1 : Writer (S1'Access); T2 : Writer (S2'Access); T3 : Writer (S3'Access); begin null; end Concurrent_Hello;
IBM's latest OO/concurrent programming language for high-performance computing (e.g. Watson) X10
TOP