pass-by-referencepascalcall-by-value

Call by Reference and Call by Value Result


Well, there was a debate on the below code between me and my friend. We're a bit confused about the output it produce. Can someone clarify the call-by-reference and call-by value result for the below piece of code?

program params;
    var i: integer;
    a: array[1..2] of integer;

    procedure p(x,y: integer);
    begin
        x := x + 1;
        i := i + 1;
        y := y + 1;
    end;

begin
    a[1] := 1;
    a[2] := 2;
    i := 1;
    p( a[i],a[i] );
    output( a[1],a[2] );
end.

The resulting output of this program in the case that the parameters are transmitted to procedure p by value-result and by reference.


Solution

  • Call by Value

    x and y in p are local variables initialized with the actual parameters, while i is a global variable, so the call p( a[i],a[i] ) is equivalent to:

    x := 1  /* The value of a[i] */
    y := 1  /* The value of a[i] */
    
    x := 2  /* x + 1 */
    i := 2  /* i + 1 */
    y := 2  /* y + 1 */
    

    and at the end the values 1, 2 are printed since they are the values of a[1], a[2] which weren't changed.

    Call by Reference

    Both x and y in p are alias for a[1] and (again) a[1] (since i = 1 when the procedure is called), so the call is equivalent to:

    a[1] := 2  /* a[1] + 1 */
    i    := 2  /* i + 1 */
    a[1] := 3  /* a[1] + 1 */
    

    and at the end the values 3, 2 are printed.

    Call by Name

    Call by Name is equivalent to Call by Reference when simple variables are passed as parameters, but is different when you pass an expression that denotes a memory location, like a subscript. In this case the actual parameter is re-evaluated each time it is encountered. So in this case, this is the effect of the call of p( a[i],a[i] ):

    a[1] := 2  /* since i = 1, the result is equal to a[1] + 1 */
    i    := 2  /* i + 1 */
    a[2] := 3  /* since i is now 2, the result is equal to a[2] + 1 */
    

    and at the end the values 2, 3 are printed. In practice the implementation calls an anonymous function (a “thunk”), each time it must evaluate a parameter.

    Call by Value Result

    Just to complete the discussion, here is the case for the value-result parameter passing, in which x and y are initialized at the beginning of the procedure execution with the values of the actual parameters, and, at the end of the execution of the procedure, are copied back to the original variables addresses:

    x := 1       /* The value of a[i] */
    y := 1       /* The value of a[i] */
    
    x := 2       /* x + 1 */
    i := 2       /* i + 1 */
    y := 2       /* y + 1 */
    
    a[1] := 2    /* the value of x is copied back to a[1] */
    a[1] := 2    /* the value of y is copied back to a[1] (not a[2]!) */
    

    and at the end the values 2, 2 are printed.

    For a discussion of the different ways of passing parameters, see for instance this.