Call-by-reference vs. Call-by-value in programming

Generally speaking, in computer programming, a parameter is a special kind of variable, used in a function declaration to refer to one of the pieces of data provided as input to that function. These pieces of data, in turn, are called arguments. Therefore, in order to make a clear distinction between them, the argument is the actual value passed to a function, procedure, or method, whereas the parameter is a reference to that value inside the implementation of the function. The act of transmitting parameter values to and/or from a called function is known as “parameter passing”. The way that the arguments are evaluated and passed to the function depends on the programming language and the kind of parameter passing mechanisms it uses. Two very common mechanisms used in many programming languages are call-by-reference and call-by-value.


On the one hand, in the case of call-by-value, the argument and the corresponding formal parameter are stored in separate storage locations. In essence, a local copy of the argument is created. Specifically, the value of the argument in the calling function is copied to a separate storage allocated for holding the formal parameter in the called function, procedure or method. Therefore, the value of the argument is used to initialize the corresponding formal parameter, which then acts as a local variable in the function. Different memory locations will be used for both variables, thus any changes made to the formal parameter will not affect the argument. This seems reasonable, because the calling function only modifies a copy of the variable’s value and does not have access to the original variable. This ensures that the actual parameter remains uncorrupted by any exception occurring during execution of the called routine.

On the other hand, rather than copying values back and forth, as in the call-by-value method, the call-by-reference mechanism passes the address of the actual parameter. This provides the access path to the cell storing the actual parameter, so that the calling function is allowed to access the parameter. In effect, the parameter is shared with the called function, because the same storage location is used for both the argument and the parameter. Duplicate space is not required, nor any copying is required. And since pass-by-reference passes a pointer to the memory location that contains the requested value, any changes made by to the parameter affect it, because they are directly made to the original value.
Most commonly, the access path is a simple pointer or a reference.

Often, confusion may arise when the programmer is not being able to distinguish the characteristics between the two argument passing mechanisms. The following programming language examples illustrate the distinction between those and try to clarify the confusion that may arise.

By definition, Java uses the pass-by-value mechanism. Consider the following Java code:

//creating an object
Object x = null;
//a method which takes an object as a parameter
printString (x);
//printing the object to the screen
System.out.println (x);
//initialization of the method
void printString (Object y)
{
y = “Example”;
}

If Java used the pass-by-reference mechanism, the output would be: Example. This would be the result, because the value of the reference is passed to the method printString(), not the variable itself.

Instead, the actual output that the programmer will get, when Java is using the pass-by-value mechanism is: null. In this case, the value “null” was passed into the method printString(), not the variable itself, so the output looks sensible.

In C++, for example, both argument passing mechanisms can be used. Consider the following code:

void f(int n) {
n++;
}

int main() {
int x = 2;
f(x);
cout < < x;
}

In this example, f’s parameter is passed-by-value; therefore any changes made to the formal parameter by the called function have no effect on the corresponding argument. Although the function increments its parameter n, this has no effect on the argument x and the value output by the program is 2 (not 3).

In the following example, nearly the same code is presented, but this time the pass-by-reference mechanism is used, therefore any changes made to the parameter do affect the argument:

void f(int &n) {
n++;
}

int main() {
int x = 2;
f(x);
cout < < x;
}

Therefore, the assignment to n in f is actually changing the variable x, so the output of this program is 3 (not 2).

For these reasons, the confusion that may arise if the characteristics of the argument passing mechanisms are not known can be significant and the difference between them is important to the programmer in several ways. First, side effect can occur, since assignments inside the function body may have different effects under pass-by-value and pass-by-reference, as it is proven by the examples above. Second, in some cases, the efficiency of the two mechanisms can differ. Pass-by-value may be inefficient if the parameter comprises of a large data structure such as a large record or array, because of all the copy operations that would have to be performed. Pass-by-reference would be more appropriate in this case, because no copies of the values of the parameters are required. However, there are at least two disadvantages to call-by-reference parameter passing. One obvious disadvantage is that the routine directly modifies the actual parameter as explained above. Thus, when the called routine fails for some reasons, whatever undesirable modifications made by the called routine are made directly to the actual parameters. Third, aliasing may occur in some cases when two names refer to the same object or location, which can cause unintended results. Moreover, aliasing may also occur when two parameters are passed by reference or one parameter passed by reference has the same location as the global variable of the procedure.

To summarize, call-by-value parameter passing has the advantage of clean semantics in the context of exception handling and aliases. However, this advantage comes at the expense of performance. Whereas call-by-reference parameter passing has the advantage of good performance but may produce unintended results in the context of aliases. Call-by-reference parameter passing may also cause corruption of actual parameters due to unhandled exceptions.