420 likes | 575 Views
Advanced Programming. Parameter Passing Giuseppe Attardi Università di Pisa. Parameter Passing. Parameter Passing. Call by value Call by reference Call by result, value/result C++ references Closures as parameters Call by name Label parameters Variable number of arguments
E N D
Advanced Programming Parameter Passing Giuseppe Attardi Universitàdi Pisa
Parameter Passing • Call by value • Call by reference • Call by result, value/result • C++ references • Closures as parameters • Call by name • Label parameters • Variable number of arguments • Function returns
Terminology • Expressions evaluate to R-values • Variables and components of variables of structured types also have an L-value, that is, an address where their R-value is stored • The assignment statement requires an L-value on the left-hand side (L stands for “left”) and an R-value on the right-hand side (R stands for “right”)
int x = 3; x = x; int v[40]; v[3] = v[3] (x == 3) = 3 = int foo(); foo = …. point.x = 12;
Value model, reference model b = 2; c = b; b = b +1; a = b + c; Value model Reference model 6 a 5 a 2 3 3 b b 2 c c 2
Example class Point { int x, y; } Point p = Point(3, 4); Point p2 = p; p.x = 5; p2.x ? foo(p); inti = 3; Integer I = new Integer(3);
C void foo (int* x) { *x = 3; } struct Point { int x, y}; void bar(Point* p) { p->x = 3; } Point p; p.x = 5; Point* p2 = &p; bar(p2);
Reference model • In language using reference model, every variable is a L-value • When it appears in a R-value context, it must be dereferenced • Usually dereference is implicit • Examples: • Algol68, Lisp, ML, Haskell, SmallTalk • Java: mixed (value for built-in types)
Call by value • The value of the R-value of the actual parameter is copied into the formal parameter at invocation
Call by result • The value of the formal parameter is copied into the actual parameter (which must have an L-value) at procedure return.
Call by value/result • The parameter is treated as in value mode during invocation and as in result mode during return.
foo (inout x) { … x …} foo1 (ref x) { … x = x + 1; … } foo1(v[3]); s = “asdasd”; foo1(s); // OK foo1(“asdasd”); // KO foo1(3); // KO int y = 7; foo1(y); y?
foo2 (Point ref q) { q = new Point(); } Point p = new Point(3,4); Point prev = p; foo2(ref p); p == prev?
void foo (ref int x) { x = x + 3; x = x/0; } int z = 2; foo(z);
Call by reference • The L-value of the formal parameter is set to the L-value of the actual parameter. • The address of the formal parameter is the same as the address of the actual parameter. Any assignment to the formal parameter immediately affects the actual parameter.
Note // C# void foo(int ref x) { x += 1; } // C++ void foo(int& x) { x += 1; } int a[3]; a[0] = 0; foo(ref a[0]); // C# foo(a[0]); // C++ foo(p);
C++ Reference Datatype • C++ provides a Reference dataype, built from other types • If T is a type T& is a new type called “reference to T” • One should avoid the confusion between the general concept of reference and a Reference Type • Also avoid the confusion with the notion of Reference types in Java and C# • Reference Types are not pointers, even though they are implemented through pointers and hence accessing a reference type may involve an implicit dereference operation • Using Reference Types in parameters even though they are still passed by value.
Reference/Value Types • In programming language theory, a reference type is a data type that can only be accessed by references • Objects of a reference type are always dynamically allocated • value type objects instead can be manipulated directly and are copied when moved (assignment, parameter passing or function return)
C++ Reference Type Example void foo(int& x) { x = x + 1; } int y = 7; foo(y); y ? foo(3); // only feasible if x was // declared as const int&
Call by name Every use of the formal parameter causes the actual parameter to be freshly evaluated in the referencing environment of the invocation point. If the formal parameter’s L-value is needed (for example, the parameter appears on the left-hand side of an assignment), the actual parameter’s L-value must be freshly evaluated. If the formal parameter’s Rvalue is needed, the actual parameter’s R-value must be freshly evaluated.
Call by name: example int sum(name intexpr, name int j, int size) { int tot = 0; for (; j < size; j++) tot += expr; return tot; } sum(A[i], i, n); /* sum of vector elements */
{ int i; int[] A; &int thunk() { return &A[i]; } sum(thunk, i, n); }
Call by macro • Every use of the formal parameter causes the text of the actual parameter to be freshly evaluated in the referencing environment of the use point.
#DEFINE foo(x) x + x foo(read()) read() + read() inline intfoo(int x) { return x + x; } intfoo(int& x, int &y) { x++; y++; return x + y;} Foo(a, a);
Esercizio • swap(x, y) using just call-by-value void swap(int x, int y) { int temp; temp = x; x = y; y = temp; }; Does not work.
swap(x, y) using just call-by-name int b[10]; swap(i, b[i]); void swap(name int x, name int y) { int temp; temp = x; x = y; y = temp; };
Note on List l = new List(); Student s = new Student(); l.add(s); float pi = 3.14; l.add(pi); (new Integer(314)).toString(); s.toString();
Note int a[] = new int[3]; int b[] = new int[5]; swap(a, b); a swap(i, a[i]); int temp; temp = x; x = y; y = temp; a=3, b=5; a=5, b=5; a=5, b=3; void swap(inoutint x, inoutint y) { int temp; temp = x; x = y; y = temp; };
Exercise • swap(x, y) using just call-by-name swap(name x, name y) => { } Does it work?
Call by name Counter example: swap(i, A[i]) (i=3, A[3] = 4) => (i=4, A[4] = 4, A[3] unchanged)
Call by value/result • swap(i, A[i])works even in case (i=2, A[2]= 99)
Call by value • Copies argument • Special cases: • array • struct typedefstruct { int x, y} Pair; Pair q; zed(q); Pair foo() { Pair p; return p; } Pair p = foo(); stack.push_back(Pair(2,3)); int [200000] v; bar(v); std::string s; bad(s);
int* foo() { int v[100]; return v; }
Closures First Class function objects
Lexical Environment of Functions • Because of nested lexical scope, even passing functions in Pascal requires passing the enclosing lexical environment
Closure in Python def makeInc(x):def inc(y): return y + xreturn inc inc3 = makeInc(3) inc10 = makeInc(10) inc3(5) # returns 8 inc10(5) # returns 15
Closure as Classes def makePair(x, y):def get(arg): if arg == ‘x’: return x elifarg == ‘y’ return y return get p = makePair(3, 5) p(‘x’) -> 3 P(‘y’) -> 5