Programming Language Features (cont.)

CMSC 330: Organization of Names & binding Polymorphism Programming Languages • Namespaces • Parametric • Static (lexical) scopes • Subtype • Dynamic scopes • Ad-hoc

Parameter Passing Parameter passing Parallelism • Call by value • Multithreading • Call by reference • Message passing • Call by name Ø Eager vs. lazy evaluation

CMSC 330 2

Parameter Passing in OCaml Call-by-Value

Quiz: What value is bound to z? In call-by-value(cbv), arguments to functions are fully evaluated before the function is invoked let add x y = x + y 7 • Also in OCaml, in let x = e1 in e2, the expression e1 let z = add 3 4 is fully evaluated before e2 is evaluated

let add x y = x + y , C++, and Java also use call-by-value 9 let z = add (add 3 1) (add 4 1) int r = 0; int add(int x, int y) { return r + x + y; } let r = ref 0 6 int set_r(void) { let add x y = (!r) + x + y r = 3; let set_r () = r := 3; 1 return 1; Actuals evaluated } let z = add (set_r ()) 2 before call add(set_r(), 2);

CMSC 330 3 CMSC 330 4

1 Call-by-Value in Imperative Languages Call-by-Value (cont.)

In C, C++, and Java, call-by-value has another Actual parameter is copied to stack location of feature formal parameter • What does this program print? 0 x 0 void f(int x) { void f(int x) { x = 3; x = 3; x 03 } } int main() { int main() { int x = 0; int x = 0; f(x); f(x); printf("%d\n", x); printf("%d\n", x); } }

• Cbv protects function arguments against modifications

CMSC 330 5 CMSC 330 6

Call-by-Reference Call-by-Reference (cont.)

Alternative idea Advantages • Implicitly pass a pointer or reference to actual parameter • Allows multiple return values • If the function writes to it the actual parameter is modified • Avoid copying entire argument to called function Ø More efficient when passing large (multi-word) arguments void f(int & x) { x = 3; x 03 Ø Can do this without explicit pointer manipulation } x Disadvantages int main() { int x = 0; • More work to pass non-variable arguments f(x); Ø Examples: constant, function result printf("%d\n", x); } • May be hard to tell if function modifies arguments • Introduces aliasing

CMSC 330 7 CMSC 330 8

2 Aliasing Call-by-Reference (cont.)

We say that two names are aliased if they refer Call-by-reference is still around (e.g., C++) to the same object in memory int x = 0; // C++ void f(int& y) { y = 1; } // y = reference var • C examples (this is what makes optimizing C hard) f(x); printf("%d\n", x); // prints 1 f(2); // error int x; int *p, *q; /*Note that C uses pointers to simulate call by reference */ Seems to be less popular in newer languages p = &x; /* *p and x are aliased */ • Older languages still use it q = p; /* *q, *p, and x are aliased */ Ø Examples: Fortran, Ada, C with pointers struct list { int x; struct list *next; } • Possible efficiency gains not worth the confusion struct list *p, *q; • The “hardware” is basically call-by-value ... Ø Although call by reference is not hard to implement and q = p; /* *q and *p are aliased */ there may be some support for it /* so are p->x and q->x */ /* and p->next->x and q->next->x... */

CMSC 330 9 CMSC 330 10

Call-by-Value Discussion Call-by-Name

Cbv is standard for languages with side effects Call-by-name (cbn) • When we have side effects, we need to know the order • First described in description of Algol (1960) in which things are evaluated • Generalization of Lambda expressions Ø Otherwise programs have unpredictable behavior • Idea: In a function: Example: • Call-by-value specifies the order at function calls Let add x y = x+y add (a*b) (c*d) = add (a*b) (c*d) • Call-by-reference can sometimes give different results (a*b) + (c*d) ç executed function Then each use of x and y in the function definition is Differences blurred for languages like Java just a literal substitution of the actual arguments, • Language is call by value (a*b) and (c*d), respectively • But most parameters are object references anyway • Implementation: Highly complex, inefficient, and provides little improvement over other mechanisms Ø Still have aliasing, parameter modifications at object level

CMSC 330 11 CMSC 330 12

3 Call-by-Name (cont.) Call-by-Name (cont.)

In call-by-name (cbn), arguments to functions What would be an example where this are evaluated at the last possible moment, just difference matters? before they're needed let cond p x y = if p then x else y Haskell; cbn; arguments let rec loop n = loop n let add x y = x + y evaluated here let z = cond true 42 (loop 0) let z = add (add 3 1) (add 4 1) OCaml; cbv; infinite add x y = x + y at call

z = add (add 3 1) (add 4 1) cond p x y = if p then x else y OCaml; cbv; arguments loop n = loop n evaluated here z = cond True 42 (loop 0) Haskell; cbn; never evaluated because parameter is never used CMSC 330 13 CMSC 330 14

Call by Name Examples Call by Name Anomalies

P(x) {x = x + x;} Write a function to exchange values of X and Y What is: Y = 2; P(Y); ç becomes Y = Y+Y = 4 Usual way - swap(x,y) { t=x; x=y; y=t; } write(Y) • Cannot do it with call by name! Reason F(m) {m = m + 1; return m;} Cannot handle both of following What is: int A[10]; • m = 1; Ø swap(A[m], m) P(A[F(m)]) Ø swap(m, A[m]) • One of these must fail becomes P(A[F(m)]) è A[F(m)] = A[F(m)]+A[F(m)] Ø swap(A[m], m) → t = A[m] ; A[m] = m; m = t; è A[m++] = A[m++]+A[m++] Ø swap(m, A[m]) → t = m ; m = A[m]; A[m] = t; // fails! è A[2] = A[3]+A[4]

CMSC 330 15 CMSC 330 16

4 Two Cool Things to Do with CBN Simulating CBN with CBV

CBN is also called lazy evaluation Thunk • CBV is also known as eager evaluation • A function with no arguments Algorithm

Build control structures with functions 1. Replace arguments a1…ak by thunks t1…tk Ø When called, t evaluates and returns a let cond p x y = if p then x else y i i 2. Within body of the function

Ø Replace formal argument with thunk invocations Build “infinite” data structures let add1 x = x + 1 in add1 (2+3) integers n = n::(integers (n+1)) take 10 (integers 0) (* infinite loop in cbv *) let add1 x = x() + 1 in add1 (fun () -> (2+3))

CMSC 330 17 CMSC 330 18

Simulating CBN with CBV (cont.) Three-Way Comparison Consider the following program under the three let cond p x y = if p then x else y let rec loop n = loop n calling conventions let z = cond true 42 (loop 0) • For each, determine i's value and which a[i] (if any) is modified Never • becomes... Get 1st arg Return 2nd arg int i = 1; invoked void p(int f, int g) { g++; let cond p x y = if (p ()) then (x ()) else (y ()) f = 5 * i; let rec loop n = loop n (* didn’t transform... *) } let z = cond (fun () -> true) int main() { (fun () -> 42) Parameters are now thunks int a[] = {0, 1, 2}; (fun () -> loop 0) p(a[i], i); printf("%d %d %d %d\n", i, a[0], a[1], a[2]); } CMSC 330 19 CMSC 330 20

5 Example: Call-by-Value Example: Call-by-Reference int i = 1; i a[0] a[1] a[2] f g int i = 1; i /g a[0] a[1] /f a[2] void p(int f, int g) { void p(int f, int g) { g++; 1 0 1 2 g++; 1 0 1 2 f = 5 * i; f = 5 * i; } 1 1 } 2 10 2 10 int main() { 5 2 int main() { int a[] = {0, 1, 2}; int a[] = {0, 1, 2}; p(a[i], i); p(a[i], i); printf("%d %d %d %d\n", printf("%d %d %d %d\n", i, a[0], a[1], a[2]); i, a[0], a[1], a[2]); } }

CMSC 330 21 CMSC 330 22

Example: Call-by-Name Other Calling Mechanisms Call-by-result int i = 1; i a[0] a[1] a[2] • Actual argument passed by reference, but not initialized void p(int f, int g) { g++; 1 0 1 2 • Written to in function body (and since passed by i++; reference, affects actual argument) f = 5 * i; a[i] = 5*i; } 2 10 Call-by-value-result 2 10 int main() { • Actual argument copied in on call (like cbv) int a[] = {0, 1, 2}; The expression a[i] isn't p(a[i], i); • Mutated within function, but does not affect actual yet printf("%d %d %d %d\n", evaluated until needed, in • At end of function body, copied back out to actual i, a[0], a[1], a[2]); this case after i has These calling mechanisms didn't really catch on } changed. • They can be confusing in cases • Recent languages don’t use them

CMSC 330 23 CMSC 330 24

6 How Function Calls Really Work Stack Frame / Activation Record

Function calls are important Machine-dependent data structure containing • Usually have direct instruction support in hardware state information for each function invocation • Detail important for programming • Allocated on stack at function invocation Ø See CMSC 216, 411, 412, or 430 • Freed upon function return (by popping stack) Contents may include Will just provide quick overview here • Local variables • Return address Key point to remember • Actual parameters • Function calls generally require allocating stack frames • Return value • Address of frame of calling function • Address of frame of lexically enclosing function CMSC 330 25 CMSC 330 26

Tail Calls Tail Recursion

A tail call is a function call that is the last thing a Recall that in OCaml, all looping is via recursion function does before it returns • Seems very inefficient • Not just function call in last line of code in function • Needs one stack frame for each recursive call let add x y = x + y let f z = add z z (* tail call *) A function is tail recursive • If it is recursive let rec len = function [] -> 0 • And recursive call is a tail call | (_::t) -> 1 + (len t) (* not tail call, performs +1 *) let rec len a = function If function is tail recursive [] -> a • Can reuse stack frame for each recursive call | (_::t) -> len (a + 1) t (* tail call *)

CMSC 330 27 CMSC 330 28

7 Tail Recursion (cont.) Tail Recursion (cont.) let rec len l = match l with l [1;2] let rec len a l = match l with a 012 [] -> 0 [2] [] -> a l [1;2][2][] | (_::t) -> 1 + (len t) l | (_::t) -> (len (a + 1) t) l [] len [1; 2] len 0 [1; 2] eax: 012 eax: 2

Function is not tail recursive Function is tail recursive • Use stack frame store return value • Same stack frame can be reused for the next call • Add 1 to return value, use as new return value • Since we’d just pop it off and return anyway

CMSC 330 29 CMSC 330 30

Short Circuiting Short Circuiting (cont.)

Will OCaml raise a Division_by_zero exception? C, C++, Java, and Ruby all short-circuit &&, || let x = 0 But some languages don’t, like Pascal if x != 0 && (y / x) > 100 then (although Turbo Pascal has an option for this): print_string "OCaml sure is fun" x := 0; if x == 0 || (y / x) > 100 then ... if (x <> 0) and (y / x > 100) then print_string "OCaml sure is fun" writeln('Sure OCaml is fun'); • No: && and || are short circuiting in OCaml • So this would need to be written as Ø e1 && e2 evaluates e1. If false, it returns false. Otherwise, it returns the result of evaluating e2 x := 0; ... Ø e1 || e2 evaluates e1. If true, it returns true. Otherwise, it if x <> 0 then returns the result of evaluating e2 if y / x > 100 then writeln('Sure OCaml is fun'); CMSC 330 31 CMSC 330 32

8