Lecture 13 Subroutines (III) Parameterized subroutines --> abstraction Passing parameters parameter modes: 1) call-by-value 2) call-by-reference: does not evaluate the argument, just figure out the L-value of the argument and pass it to function 3) call-by-value/result formal parametes v.s. actual parameters (arguments) e.g., fun fact(n) = .... (* n is formal parameter, where you define the function *) fact (5); (* 5 is actual parameter, when you call the function *) Reasons to call by reference: o if you want to return multiple things. o efficient. e.g., a large array. call-by-value will copy the whole array. Problems with call-by-reference o happens when more than one way to refer to the same thing, i.e., aliasing. e.g., 10 5 void swap( int &x, int &y) { x = x + y; // x = 15 y = x - y; // y = 10 x = x - y; // x = 5 } // this artificial version of code tries to save space // from assigning a temp variable. swap(a, a); or swap(a[i], a[j]); if a[i] and a[j] point to the same location, swap will return 0, which is wrong! This problem can be resolved by call-by-value/result (copy in / copy out) The subtlety with call-by-value/result is the order to copy out results. e.g., int COUNT = 0; void f (int &y) { y += 10; COUNT++; } f(COUNT); // if count = 5, this will return // 16 if call-by-reference; // 15 if call-by-value/result // 5 if call-by-value Languages that defines a single set of rules for all parameters: C, Fortran, ML, Lisp, ... Languages that provides two or more sets of rules: Pascal, Ada, Modula, ... How would call-by-x affect our implementation of interpreter? by-value: | seval( App(e1, e2) env sto = let val (x, body, senv,sto1) = getFn(senv, e1 env sto) val (v, sto2) = seval e2 env sto1 val loc = newLoc() val senv' = insert x loc senv val sto3 = insert loc v sto2 in seval body senv' sto3 end by-reference: in this mini language, only var has L-value | seval ( App(e1, Var y) env sto = let val (x, body, senv, sto1) = getFn(seval e1 env sto) val loc = lookup y env val senv' = insert x loc senv in seval body senv' sto1 end by-value/result: get desirable properties of call by reference for being able to return multiple things from a function call and avoid aliasing problem. fun copy (from_loc, to_loc, sto) = let val v = lookup from_loc sto in insert to_loc sto end | seval ( App(e1, Var y) env sto = let val (x, body, sevn, sto1) = getFn(seval e1 env sto) val yloc = lookup y env val xloc = newLoc () val senv' = insert x xloc senv val sto2 = copy yloc xloc sto1 val (v, sto3) = seval blody senv' sto2 (* do not change y *) val sto4 = copy xloc yloc sto3 (* until the end *) in (v, sto4) end