程序代写代做 Erlang Lambda Calculus data structure Java Haskell C Parameter Passing

Parameter Passing
CSE 216 : Programming Abstractions Department of Computer Science Stony Brook University Dr. Ritwik Banerjee

Pass by value
• Also known as “call by value”.
• The arguments to a function are fully
evaluated before the function is invoked.
• The resulting value is copied into a location. This location is used to hold the argument’s value during the method execution.
– In Java, this ‘location’ is typically a chunk of memory in the runtime stack for the application.
• Java is strictly pass by value.
– People who claim otherwise are like flat-earthers. Avoid them.
1
© 2019 Ritwik Banerjee

Pass by value
“In Java, objects are passed by reference and primitives are passed by value.”
• You may often hear statements like that, but this is #fakenews.
• Primitives are, of course, passed by value. But objects are not passed by reference!
• Object references (i.e., pointers) are passed by value.
– This may look like we’re splitting hairs, but it’s actually an important issue.
2
© 2019 Ritwik Banerjee

public class Dog { String name; String bark;
public Dog(String name, String bark) { this.name = name;
this.bark = bark;
} }
public static void foo(Dog d) {
d = new Dog(“Fifi”, “bow-wow”);
}
public static void main(String[] args) {
Dog aDog = new Dog(“Max”, “woof”);
foo(aDog);
System.out.println(aDog.bark); // woof, not bow-wow System.out.println(aDog.name); // Max, not Fifi
}
Example

What happened to Fifi?
• Rememberthatobjectreferencesarepassedbyvalue.
– That is, an object itself is never passed to
foo(Dog).
– The object itself is in the heap, exactly where it was
before the method was called.
• Thinkofballoonsinstead.
• Callingafunctionislikeatyinganewstringtothat same balloon, and passing on that string to the function.
• Butifthefunctionsays“=newBalloon()”, it is creating a new binding to var, and leaving the old balloon alone.
– So then, no matter what it does using the variable name (the new balloon), the old one remains unaffected.
– Fifi went to a farm. No, seriously, you just never accessed a pointer to that farm. Fifi is fine!
4
© 2019 Ritwik Banerjee

public class ParameterPassing {
static int r = 0;
static int add(int x, int y) { return r + x + y;
}
static int setR() { r = 3;
return 1; }
public static void main(String[] args) { System.out.println(add(setR(), 2));
} }
Example

References in OCaml
• ThereftypeisapolymorphictypethroughwhichOCamlsupportssome amount of imperative programming.
• Avalueofthetypeintref,forexample,isapointertoalocationin memory.
• Itisanalogoustoint*inCandC++,orInteger(butnottheprimitivetype int) in Java.
• Thede-referencingisdonebythe“!”operator.Forexample,!xdenotesthe contents of the memory location to which x was pointing. In newer version of OCaml, this has been replaced by x.val.
• Toupdatethecontentsofareftype,simplyuse x :=
6
© 2019 Ritwik Banerjee

OCaml
In a let statement such as
let x = e1 in e2
the expression e1 is fully evaluated before e2 is evaluated.
What value is bound to z below?
let add x y = x + y;;
let z = add 3 4;;
let z = add (add 3 1) (add 4 1);;
What about in the following code?
let r = ref 0;;
let add x y = (!r) + x + y;;
let set_r () = r := 3; 1;; (* this is not functional *) let z = add (set_r ()) 2;;
7
© 2019 Ritwik Banerjee

Passing primitives by value in imperative languages
• InC,C++,andJava,functionargumentsareprotectedagainst modifications. For example, the code below prints 0 instead of 3:
static void f(int x) { x = 3; }
static int x = 0;
public static void main(String[] args) { f(x);
System.out.printf(“%d\n”, x); }
8
© 2019 Ritwik Banerjee

Pass by name
• Also known as “call by name”.
• This was first described in lambda calculus, and then in early programming languages like Algol.
• The main idea is that in a function, each use of a parameter is a literal substitution of the actual argument expression. For example, if the following had pass by name
let add x y = x + y;; add (a*b) (c*d);;
the actual execution would be
add (a*b) (c*d) = (a*b) + (c*d);;
• The implementation is highly complex, and inefficient.
9
© 2019 Ritwik Banerjee

Pass by name
• In terms of evaluation, the arguments to functions are evaluated as late as possible, just before they are needed.
• To compare the pass-by-value of OCaml with the pass-by-name of Haskell:
letaddxy =x+y;;
let z = add (add 2 1) (add 3 2);;
OCaml pass by value: arguments are evaluated here
add x y = x + y
z = add (add 2 1) (add 3 2)
Haskell pass by name: arguments are evaluated here
10
© 2019 Ritwik Banerjee

Pass by name
• Basedonthedifferenceofwhereanexpressionis evaluated, we can have programs that behave very differently.
• WithOCaml’scall-by-value,theexpressionsare evaluated before being passed to a function. So
let f predicate x y =
if predicate then x else y;;
let rec g n = g n;; (* infinite recursion *) let z = f true 2 (g 2);;
will be an infinite recursion.
• WithHaskells’call-by-name,however
f predicate x y = if predicate then x else y gn=gn
z = f true 2 (g 2)
the last (g 2) is never evaluated, it is passed as is, and the program terminates properly.
11
© 2019 Ritwik Banerjee

Pass by name
• Pass-by-name is complex and often inefficient, but still finds an important place in programming.
• By now you might have already realized that pass- by-name does lazy evaluation, while pass-by- value does eager evaluation.
• Due to the lazy behavior, pass-by-name is very useful in creating non-strict programs that are
1. control structures of the type if predicate then x else y
2. infinite data structures like streams integers n = n :: (integers (n + 1))
take 5 (integers 0)
Note: the above code is in Haskell. This will not work in OCaml, and cause a stack overflow due to infinite recursion.
12
© 2019 Ritwik Banerjee

Thunks
A thunk is a subroutine used to inject an additional calculation into another subroutine.
They are primarily used to delay a calculation until its result is needed, or to insert operations at the beginning or end of the other subroutine.
This is usually done by taking an function, and replacing each argument with a thunk that evaluates that argument.
Thunks are the standard way to simulate lazy call-by-name evaluation in a language that normally does eager call-by-value evaluation.
13
© 2019 Ritwik Banerjee

Thunk for lazy evaluation
• InJava,acalltothefunctionnorm(double,double) will immediately spend resources on the arithmetic operations, even if the result is not used immediately in the code:
static double norm(double x, double y) { return Math.sqrt(x * x + y * y);
}
public static void main(final String[] args) { double immediate = norm(2,3);
}
• ButwecancallaSupplierasfollows: public static void main(String[] args) {
Supplier norm23 = () -> norm(2, 3);


double laterWhenNeeded = norm23.get(); }
14
© 2019 Ritwik Banerjee

Thunk for lazy evaluation
• Let’srevisittheOCamlexampleandseehowwecanuse thunks to do lazy evaluation. Here’s the original code, which goes into infinite recursion:
let f predicate x y =
if predicate then x else y;;
let rec g n = g n;;
let z = f true 2 (g 2) in z;;
• Andhereisthenewcode,wherewedidnotchangethe definition of g, but we completely changed how z is
evaluated, by using one thunk for each argument:
let f predicate x y =
if (predicate()) then (x()) else (y());;
let rec g n = g n;;
let z = f (fun () -> true)
(fun () -> 2)
(fun () -> g 2)
in z;; (* evaluates to 2 *)
15
© 2019 Ritwik Banerjee

Pass by reference
• Inpassbyvalue,thecontent(oftheargument)ispassedbythecallerto the invoked function (the callee).
static void f(String s) { s = “f(String)”;
}
public static void main(String[] args) { String s = “main(String[])”;
f(s);
System.out.println(s);
}
s
“f(String)”
s
“main(String[])”
16
© 2019 Ritwik Banerjee

Pass by reference
• Inpassbyreference,areference(oftheargument)ispassedbythecaller to the invoked function (the callee).
static void f(String s) { s = “f(String)”;
}
public static void main(String[] args) { String s = “main(String[])”;
f(s);
System.out.println(s);
}
s
“f(String)”
s
17
© 2019 Ritwik Banerjee

Pass by reference
Advantages
•Allows multiple return values
•Avoid copying entire argument to the callee.
•More efficient when passing large arguments. •Can do this without explicit pointer manipulation
Disadvantages
•More work to pass non-variable arguments like constants. •Hard to tell if function modifies arguments
•Introduces aliasing.
•But why is aliasing potentially a disadvantage?
18
© 2019 Ritwik Banerjee

Aliasing & pass by reference
• Recall: objects are said to be aliased if they refer to same object in memory.
• C examples to illustrate why this can be confusing …
19
© 2019 Ritwik Banerjee

A comparison of parameter passing conventions
Let’s see what is the value of i and which a[i], if any, is modified under
the following:
a) pass by value
b) pass by reference
c) pass by name
20
© 2019 Ritwik Banerjee

Pass by value
• The variablegis a copy ofi, sog++
does not change i. So the value of i finally printed is 1.
• Thelocalvariablesfandghave values 5 (because, again, g++ doesn’t change i) and 2, respectively.
21
© 2019 Ritwik Banerjee

Pass by reference
• Thevariablegreferstothesame variable i, so g++ increments i. So the value of i finally printed is 2.
• Thelocalvariablesfandghave values 10 (because g++ increments i) and 2, respectively.
22
© 2019 Ritwik Banerjee

Pass by name
• Pass by name substitutes the argument with the passed expression, and evaluates it only when needed.
• So, even inside the function p(), we have the expressions a[i] and i, and not f and g.
• Therefore, the value of i is changed by g++ and the printed value of i is 2.
• In p(), f is substituted by a[i], which is evaluated in the line f = 5 * i. At that point, i = 2, so a[2] takes the value 10 (we still have the unchanged values a[0] = 0 and a[1] = 1).
23
© 2019 Ritwik Banerjee

An implementation note: short circuit evaluation
• Mostmodernlanguagesintroduceshortcircuitevaluationforcontrol structures and Boolean constructs. This is often an additional implementation in the language, irrespective of whether they use normal or applicative order in general.
• Forexample,&&and||are“short-circuited”inOCaml.
– In e1 && e2, e1 is evaluated first. If false, it returns false. Otherwise, it
returns the result of evaluating e2.
– In e1 || e2, e1 is evaluated first. If true, it returns true. Otherwise, it returns
the result of evaluating e2.
• Similarly,Javaalsoshort-circuits&&and||.Sodomanyotherlanguages
like C, C++, Ruby, etc.
– Some older languages like Pascal do not.
– Note: Do NOT confuse these Boolean operators with bitwise operations & and |, which are eagerly evaluated in C, C++, Java, Python, etc.
24
© 2019 Ritwik Banerjee