<<

IA010: Principles of Programming Languages

4. Control Flow

Jan Obdržálek obdrzalek@fi.muni.cz

Faculty of Informatics, Masaryk University, Brno

IA010 4. Control Flow 1 Evaluation order

For imperative languages the order of evaluation is of utmost importance.

What affects the order?

1 expression evaluation order 2 sequential order of statements 3 branching (conditional statement, unconditional jumps) 4 iterations (loops) 5 6 7 concurrent 8 9 nondeterminism

IA010 4. Control Flow 2 Outline

Expressions

Assignment statements

Control statements Selection statements Iterative statements (loops) Iteration over data structures Other branching constructs

IA010 4. Control Flow 3 Expressions

IA010 4. Control Flow 4 Expressions

• fundamental means of expressing computation (in any programming paradigm) • built from • simple objects (constants, variables), using • function/operator application, and • parentheses • expression types: • arithmetic • boolean • relational Operators and operands • operator – built-in function, special syntax • typically does not need parenthesis • placement: prefix, infix, postfix • operand – operator argument

IA010 4. Control Flow 5 Operator evaluation order

• For prefix/postix notation the order is implicit. • For infix operators given by 1 precedence rules 2 associativity rules

Precedence (priority) • states which operators are “more important” • these are evaluated first • the number of levels is language-dependent

Associativity • how to group operators with the same priority? • left-to-right, or right-to-left • can depend on the operator

IA010 4. Control Flow 6 Example: operator precedence

Operator Type Operator Associativity Primary () [] . -> expr++ expr-- left-to-right Expression Operators Unary Operators * & + - ! ∼ ++expr right-to-left --expr (typecast) sizeof Binary Operators * /% left-to-right + - << >> < > <= >= == != & ˆ | && || Ternary Operator ?: right-to-left Assignment = += -= *= /= %= >>= <<= right-to-left Operators &= ˆ= |= Comma , left-to-right

IA010 4. Control Flow 7 Possible problems

1 unsuitable/too coarse priority hierarchy (Pascal)

ifA relational op. > boolean op. 2 exponentiation priority

A ** B ** C! -- associates to the right Ada: malformed expression, parentheses necessary 3 unary v. binary operators

a + - b + c // what should we do here?

(illegal, solution: a + (-b) + c) Programmers rarely remember the precedence hierarchy! Using parentheses saves lots of headache.

IA010 4. Control Flow 8 Operand evaluation order

Example 1 Example 2 a = 10; inta=5; b = a + foo(a); int bar() { a = 17; /* what if foo changes */ return 3; /* the value ofa to 20? */}

void main() { a = a + bar(); } side effects • if a function changes either 1 one of its parameters, or 2 a global variable • remember: mathematics does not know side-effects!

IA010 4. Control Flow 9 Operand evaluation order II

How to deal with side-effects? 1 prohibit them (problematic – e.g. no writing to globals in functions) 2 give a fixed operand evaluation order e.g. Java (left-to-right) (limits possible compiler optimization)

Referential transparency • two expression with the same value can be swapped one for the other with no effect on the result • if no side-effects, result1 = result2 result1 = (fun(a) + b) / (fun(a) - c); temp = fun(a); result2 = (temp + b) / (temp - c); • advantages: programs are easier to understand • true for purely functional languages IA010 4. Control Flow 10 Operator overloading

• if one operator name is used for a number of different operations (e.g. “+” for both integer and real ) • acceptable, if such an operator does not decrease • readabilty • reliability • problematic overloading example: x = &y; (“&” is either bitwise-and or address-of operator (by context) ) • a similar problem: minus (unary, binary) (ML solution: two different symbols ~ and -) • C++, C#: user-overloaded operators (but e.g. “::” and “.” cannot be overloaded) (Java does not allow user-overloaded operators) • suitable usage: A * B + C * instead of MatrixAdd(MatrixMult(A,B), MatrixMult(C,D))

IA010 4. Control Flow 11 Short-circuit evaluation

• the result can be determined without evaluating all operands/operators • can be very useful, e.g. in the following code:

index = 0; while ((index < listlen) && (list[index] != key)) index = index + 1;

• subtle errors when combined with side-effects:

(a > b) || ((b++) / 3)

• languages with short-circuit evaluation: C-based languages, ML, #, Python . . . • Ada: both versions – and/and then; or/or else (best of both worlds)

IA010 4. Control Flow 12 Assignment statements

IA010 4. Control Flow 13 Assignment statements

• the assignment statement is one of the central constructs in imperative languages • dynamically alters bindings of values to variables conditional targets

($flag ? $count1 : $count2) = 0;# compound assignment operators • shorthands for oft-used forms of assignment a = a + b =⇒ a += b unary assignment operators • ++ (increment) and -- (decrement) • both prefix and postfix versions • stand-alone (count++;) or in expressions (a = count++;)

IA010 4. Control Flow 14 Assignment statement II multiple assignment

($first, $second, $third) = (20, 40, 60); ($first, $second) = ($second, $first); assignments as expressions • assignment statement can return a value • in that case it can be used in place of an expression • examples: C-style languages, JavaScript, Perl

while ((c = getchar()) != EOF) {...}

(parentheses are necessary, low priority of "=") • possible problems: • introduces side-effects: a = b + (c = d/b) - 1 • less effective error detection: if (x=y) vs if (x==y)

IA010 4. Control Flow 15 Control statements

IA010 4. Control Flow 16 Control statements

• change the flow of execution of a program • control structure • control statement plus • the collection of statements, whose execution it controls • we distinguish • selection statements • iterative statements • uncoditional branching ()

Theorem (Böhm, Jacopini 1966) All that can be expressed by flowcharts can be coded in a with two control statements: a choice between two paths and logically controlled iterations.

Corollary: goto is superfluous

IA010 4. Control Flow 17 Two-way selection statement

The general form: if control_expression then clause else clause

Main issue: selectors Typical syntax in BNF:

-> if then | if then else

Which if does the else belong to in the code below? if (sum == 0) if (count == 0) result = 0; else result = 1;

IA010 4. Control Flow 18 Matching else to if

Several approaches have been used: • nearest previous unpaired then clause (Java) • all then and else clauses must be compound (Perl) • compulsory indentation (Python, F#) • explicit end of if (Fortran, Ada, Ruby) if sum == 0 then if sum == 0 then if count == 0 then if count == 0 then result = 0 result = 0 else end result = 1 else end result = 1 end end

IA010 4. Control Flow 19 Multiple-selection statements switch (expression) { //C case constant_expression_1: statement_1; ... case constant_expression_n: statement_n; [default: statement_(n+1)] } Branching at the end of segments • at the end of a segment the control can be transfered • to the next segment (fall-through) • to some other segment (goto) • after the selection statement letter_case = lower; switch (c) { case 'A' : letter_case = upper; // fall through case 'a' : ... break; ... IA010 4. Control Flow 20 } Multiple-selection statements III

C/Java: • no implicit branching (rarely used) • branching can be requested explicitly using break • case can be almost anywhere in C (disallowed in Java) switch (x) default: if (prime(x)) case 2: case 3: case 5: case 7: process_prime(x); else case 4: case 6: case 8: case 9: case 10: process_composite(x);

IA010 4. Control Flow 21 Multiple-selection statements III

C#: • requires explicit branch statement (break/goto) at the end of each segment • braching expressions can be of type string

Perl, Python: no multiple-selection statement switch vs a chain of if-then-else statements • if can use any condition (e.g. < 1, < 10, < 100) • switch evaluates the expression only once • to increase the readability of nested if-then-else constructions keywords elif/elseif are often introduced

IA010 4. Control Flow 22 Iterative statements (loops)

basic classification – according to 1 the condition used • loops with a counter (for) • loops with a boolean condition (while-do, do-while, repeat-until ...) • combination of the two 2 location of the control mechanism • top of the loop (test is performed before executing the loop) • bottom of the loop (test is performed after executing the loop) alternative to loops: iterating over data structures

IA010 4. Control Flow 23 Counter-controlled loops

10 FOR I = 1 TO 100 STEP 2

• associated loop variable • loop parameters • initial value • terminal value • step size C-based languages for (expression_1; expression_2; expression_3) loop body

• combines counting and logical control • all expressions and body are optional • in C89 the test is expression_2 > 0 • loop variable(s) can be modified in the loop body! (disallowed in Ada)

IA010 4. Control Flow 24 Counter-controlled loops II

Python for loop_variable in object: loop_body [else: else clause] Examples: for xxx in [42, 50, 1729] for yyy in range(5)# [0,1,2,3,4]

Purely functional languages //F#- counter loop emulation let rec forLoop loopBody reps = if reps <= 0 then () else loopBody() forLoop loopBody (reps - 1);;

IA010 4. Control Flow 25 Logically-controlled loops

• while-do, do-while, repeat-until ... • more general than counter controlled loops • in C it is legal to branch into the loop bodies • tests at the end are • rarely useful • somewhat dangerous (loop will be executed at least once)

Functional languages – replaced by recursion let rec whileLoop test body = if test() then body() whileLoop test body else ();;

IA010 4. Control Flow 26 User-located loop control

• we can finish early: • the whole loop (break) • just one iteration (continue) • for nested cycles using labels (Java) • often combined with “infinite” loops • replaces common need for goto statements while (sum < 1000) { getnext(value); if (value < 0) break; sum += value; }

IA010 4. Control Flow 27 User-located loop control: Python

for num in range(10,20):#to iterate between 10 to 20 fori in range(2,num):#to iterate on the factors of the number if num%i == 0:#to determine the first factor j=num/i#to calculate the second factor print '%d equals %d * %d' % (num,i,j) break#to move to the next number, the#first FOR else:# else part of the loop print num, 'is a prime number'

IA010 4. Control Flow 28 Iteration over data structures

simple form: over sets of values Do Count = 1, 9, 2 ! Fortran for count in range [0, 9, 2]: # Python

General data-based iteration: • using the associated iterator • iterator properties: • returns an element of the structure every time it is called • has a history (remembers, which element was returned last) • important in object-oriented languages (frequent use of abstract data types, mainly collections)

IA010 4. Control Flow 29 Examples of iterator use

Java 5.0 (myList is an ArrayList of strings) for (String myElement : myList) { ... }

(the collection must implement the Iterable interface)

C# (names is a List of strings) foreach (String name in names) Console.WriteLine(name); simulating iteration in C for (ptr = root; ptr == null; ptr = traverse(ptr)) { ... }

(traverse acts as an iterator)

IA010 4. Control Flow 30 Unconditional branch statement

The unbridled use of the go to statement has as an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress. . . . The go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one’s program. (Edsger Dijkstra. "Go To Statement ". Communications of the ACM 11 (3): 147–148. doi:10.1145/362929.362947)

• originated in hardware • better options (by location) • end of function: return • end of iteration/loop: break/continue • error state handling: exceptions • “safe” use of goto – jump only forward (cannot create a loop!) • goto-free languages: Java, Python • languages with goto: Fortran, C, C# IA010 4. Control Flow 31 Guarded commands

if -> [] -> [] ... [] -> fi

• each branch is “guarded” by a condition • when executed all conditions are evaluated • if more than one test suceeds, the branch is chosen nondeterministically • related to concurrency and verification • used to define functions in Haskell (patterns) if x >= y -> max := x [] y >= x -> max := y fi

IA010 4. Control Flow 32