CPS 343/543 Lecture notes: Parameter-passing mechanisms



Coverage: [EOPL] §3.8 (pp. 107-114)


call-by-value vs. call-by-reference

  • sample program on p. 108
    • references a and x are distinct
    • graphical depiction of call-by-value (result is 3)



    • graphical depiction of call-by-reference (result is 4)



  • C only supports call-by-value
  • in C we simulate call-by-reference by passing the address of a variable by value
    #include<stdio.h>
    
    /* swap call-by-value */
    void swapCbV (int x, int y) {
       int temp = x;
       x = y;
       y = temp;
    }
    
    /* swap call-by-reference */
    void swapCbR (int* x, int* y) {
       int temp = *x;
       *x = *y;
       *y = temp;
    }
    
    main() {
    
       int a = 1;
       int b = 2;
    
       swapCbV (a, b);
    
       printf ("    call-by-value: ");
       printf ("a = %d, b = %d\n\n", a, b);
    
       swapCbR (&a, &b);
    
       printf ("call-by-reference: ");
       printf ("a = %d, b = %d\n\n", a, b);
    }
    
  • why cannot a swap function be written in Java?
  • why might we want to use call-by-reference? to simulate the return of more than one value
  • FORTRAN was the first language to use call-by-reference


Implementing call-by-reference in our interpreter

  • currently are interpreter only supports call-by-value. why? because every time we encounter an operand, we create a new reference
    • call-by-value: create new reference for every evaluation of an operand
    • call-by-reference: create new reference for only evaluation a non-variable operands
  • let's retain
      denoted value = ref(expressed value)
      expressed value = number + procvalue
  • we only create a new reference for non-variable operands (e.g., literals)


New implementation of references

  • now the vector element to which reference refers can contain either an expressed value or denoted value (i.e., a reference to an expressed value)
  • the former is called a direct target while the latter is called an indirect target
  • new reference implementation in Fig. 3.17 on p. 111



  • (regenerated from [EOPL] Fig. 3.18 on p. 113)


Re-instrumentation of eval-rand

  • the procedures extend-env and apply-env-ref need not change
  • consider where subexpressions are evaluated:
    • primitive applications,
    • let's, and
    • user-defined procedure applications
  • we use call-by-value for the first two and call-by-reference for the last
    • code for primitive applications on p. 110 (essentially same as original)
    • code for let's on p. 112 (essentially same as original)
    • code for user-defined procedure applications on p. 112 (now eval-rand has changed):
      (define eval-rand
         (lambda (rand env)
            (cases expression rand
      
               ;; if the operand is a variable, then it denotes a location
               ;; containing an expressed value, so we want to return an
               ;; _indirect target_ pointing to that location
               (var-exp (id)
                  (indirect-target
                     (let ((ref (apply-env-ref env id)))
      
                        (cases target (primitive-deref ref)
      
                           ;; if the variable is bound to a _location_ which
                           ;; contains a direct target, we return
                           ;; an indirect target to that location
                           (direct-target (expval) ref)
      
                           ;; but if the variable is bound to a _location_
                           ;; which contains an indirect target, then
                           ;; we return the same indirect target
                           (indirect-target (ref1) ref1)))))
      
               ;; if the operand is a non-variable, then we create a new
               ;; location, as before, by returning a _direct target_ to it
               ;; (i.e., call-by-value)
               (else (direct-target (eval-expression rand env))))))
      
      3 cases:
      • operand is a non-variable (e.g., literal): return a direct target to it
      • operand is a var-exp which points to a direct target: return an indirect target to it
      • operand is a var-exp which points to a indirect target: return an copy of the same indirect target


Illustrative example on p. 113


Call-by-result

  • how does the caller reference the computed value if it is a literal or an expression?
  • parameter collision [COPL]
       fun(a,a);
    
       fun(x,y) {
         x = 1;
         y = 2;
       }
       
  • when should address of actual parameters be evaluated? at time of the call or at time of the return?


Call-by-value-result

  • combination of call-by-value and call-by-result, and shares the problems of both
  • sometimes referred to as call-by-copy-restore


Sample code snippet

    note: Pascal-style code is used only for illustration; use not intended to convey that Pascal uses these mechanisms.
    procedure p (integer x, integer y) begin
       x = x + 1;
       y = y + 1;
    end;
    
    begin
       a = 1;
       p (a, a);
       (* what is the value of a here? *)
       print a;
    
      (* if call-by-value used, a=1
         if call-by-value-result, a=2
         if call-by-reference used, a=3
      *)
    end.
    


Simple classification

to think about each of the parameter-passing mechanisms
  • call-by-value (IN)
  • call-by-result (OUT)
  • call-by-value-result (also called call-by-copy)
    • IN at the front
    • OUT at the back
  • call-by-reference (IN-OUT)
  • call-by-name
    • lazy evaluation
    • akin to #define in C

  • call-by-value-result (IN-OUT) != call-by-reference (IN-OUT)


References

    [COPL] R.W. Sebesta. Concepts of Programming Languages. Addison-Wesley, Boston, MA, Sixth edition, 2003.
    [EOPL] D.P. Friedman, M. Wand, and C.T. Haynes. Essentials of Programming Languages. MIT Press, Cambridge, MA, Second edition, 2001.

Return Home