Parameter Passing Semantics: Fall 21

Goal: Explore various different parameter passing schemes and typing of functions.

What will be covered ?


Subprograms/subroutines/functions and Parameters

Reference Memory vs Value model:


Parameter Passing Mechanisms

  • One of the most important design decisions is which parameter passing methods are implemented
  • Pass by Value (Pass by assignment, Pass by sharing)
  • Pass by Result
  • Pass by Value Result (also called Copy in, Copy out)
  • Pass by Reference
  • Pass by Name


  • Pass by Value (Pass by "assignment")  



    Pascal, Java and Modula-2 parameters are treated like initialized local variables
  • Assignments to the parameters do not cause changes outside the subprogram
  • Ada: The in parameter may not be assigned to
  • Java: The keyword final prevents assigning to the parameter at all.

  • What kinds of methods can not be easily coded?

    Evaluation of parameters
  • Order of evaluation of parameters with side effects can be resolved by insisting on an order in evaluating (right to left or left to right).
  • Java enforces the above
  • Most languages the evaluation order is implementation dependent.

  • Parameter Evaluation and Side Effects
  • Try on a variety of C and C++ compilers: 
  • y = -1;
    upOnly(++y, ++y);
  • Some implementations evaluate the first parameter (and modify it) before the second, others evaluate the last parameter first.
  • Some language definitions make this dependency an error.

  • Pass by Reference

    program Test();
    var innocent :integer;

    procedure modify(var Share: integer);
    begin
    Share := Share + 3;
    end;
     begin
    innocent := 100;
    modify(innocent) {upon return innocent is 103}
     end;  
     
    The parameter becomes an alias for the argument.
  • Simulation of pass by reference
  • C & Algol68: A pointer is used to pass a location explicitly.
  • In C:  pass by value (assignment) a pointer type.
  • void refer (int *x) {
    *x += 1;
    }
    int main() {
    int a;

    refer(&a);
    }
    void refer(int& x){
    x += 1;
    }
    void fun() {
    int  a;
    ...
    refer(a);
    }
    void f() {
    int i;
    int &r = i; // r refers to i
    r = 9; // the value i becomes is 9
    int * p = &i; // p points to i
    int & rr = r ; // rr refers to i
    }
    procedure swap (var x: integer,
                    var y: integer);
    var z:integer
    begin
    z:=x;
    x:=y;
    y:=z;
    end
    }

    R-Value references & move constructor c++ 11

    Pass by Value-Result

    a : INTEGER;
    PROCEDURE p(x,y: IN OUT INTEGER) is

    BEGIN
    x := x + x ;
    y := y + y;
    END;

    BEGIN

    a := 1;
    p(a,a);
    END;

    Issues left unspecified

    Another Swap :

    PROCEDURE Main IS
    PROCEDURE Swap(x,y: IN OUT integer) is
      BEGIN
    x := x + y;
    y := x - y;
    x := x - y;
      END;
      BEGIN
        a := 1;

        Swap(a,a);
       
      END;
     
    PROCEDURE MAIN
    PROCEDURE Swap(VAR x,y: integer);
      BEGIN
    x := x + y ;
    y := x - y ;
    x := x - y ;
      END;
     BEGIN
       a:= 1;
       Swap(a,a)
     END




    Pass by Name 

    int i;
    int a[ ] = new int[2];
    void p(x) {  //pass by name
    i = i + 1;
    x = x + 1; 
    }
    void main() {
    i = 0;
    a[0] = 0;
    a[1] = 1;
    p( a[i] );
    }
  • just substitute the actual parameters textually in place of the formal parameters.
  • In fact, each reference to a call by name reference is implemented by
  • jump out to the argument (called a "thunk" )
    execute the argument expression
    jump back into the routine
  • Thus the above would be
  • in main: i = 0;
          a[0] = 0;
          a[1] = 1;

    in p(x):
         i = i + 1;
         a[i] = a[i] +1;


    Functional Languages and Pass by Name


    Macro expansion vs. procedure "pass by name"

    #define name ( name1, name2, ...) body 
    name ( arg1, arg2 ...)
    #define sum(x,y)   x+y
    result = sum ( a, 3*a +b );
           with
    result = a  + 3*a +b;
    1. substitute text of macro call's argument for each occurrence of nameX in body
    2. substitute resulting body for the macro call
        #define swap(a,b) { int t; t=a; a=b; b=t; }
    then
          swap( i, A[i] ) ;
    becomes
         { int t; t=i; i=A[i]; A[i]=t; };
    Both call by name and macro have a "side effect" problem -- changing i's r-value changes A[i] l-value.
    float e =2.71828;
    #define p(x) (x/e)
    ...
    int f (int e ) {
       ...
       p(z);
       ...

    }
    float e =2.71828;

    ...
    int f (int e ) {
       ...
       (z/e);  /* DIVIDES the WRONG "e" */
       ...

    }

    Some additional variations : Default Parameter Values

  • Conformant Arrays
  • Variable number of arguments
  • int get_word(char*, int &, int start = 0);
    TYPE intptr is ACCESS integer;

    FUNCTION Get_word(C : String; X : intptr; Start : integer := 0 ) RETURN Integer;

  • Both languages parameters with default values can be omitted
     
  • Otherwise, function calls would be ambiguous
  • V := Get_word( Start => 1,C => "abc",
                   X => new integer(1)

                  );

    The existence of named parameter passing forces Ada to require that parameter names be provided in the subprogram declaration.
    def func(spam, eggs, toast=0, ham=0):
         print (spam,eggs,toast,ham)
    func(1,2)

    OR

    func(1,2, ham=1,toast=0)

    Or


    func(1, eggs=99)

    Or

    func(1,2,3,4)