Write a post

Enjoy this post? Give Michael Safyan a like if it's helpful.

Beginner's Guide to Passing Parameters

Published Mar 25, 2016Last updated Mar 28, 2017
Beginner's Guide to Passing Parameters

Overview

No programming language course would be compete without a discussion of pass-by-value and pass-by-reference. Understanding the difference between the two is important in order to understand the engineering tradeoffs that go into the creation of a programming language, as well as to write correct, bug-free code based on accurate assumptions about how the language works.

Parameter Passing Techniques

There are a number of different ways a programming language can pass parameters:

  1. Pass-by-value
  2. Pass-by-reference
  3. Pass-by-value-result
  4. Pass-by-name

The most common are pass-by-value and pass-by-reference. C++ supports both techniques, while most other languages (Java, JavaScript, Python, etc.) use pass-by-value exclusively.

Pass-by-value

Consider the following pseudo-code:

Or, equivalently, the real C++ code (using pass-by-value):

#include <iostream>
#include <cstdlib>

void AssignTo(int param) {
  param = 5;
}

int main(int argc, char* argv[]) {
  int x = 3;
  AssignTo(x);
  std::cout << x << std::endl;
  return 0;
}

In a pass-by-value system, the statement AssignTo(x) creates a copy of the argument x. This copy has the same value as the original argument (hence the name "pass-by-value"), but it does not have the same identity. Thus the assignment within AssignTo modifies a variable that is distinct from the supplied parameter. Thus, the output in this passing style is 3 and not 5.

Pass-by-reference

Let's consider the same example pseudo-code once again:

Or, equivalently, the real C++ code (using pass-by-reference):

#include <iostream>
#include <cstdlib>

void AssignTo(int& param) {  // use of ampersand (&) implies reference
  param = 5;
}

int main(int argc, char* argv[]) {
  int x = 3;
  AssignTo(x);
  std::cout << x << std::endl;
  return 0;
}

In a pass-by-reference system, the function invocation does not create a separate copy of the argument; rather, a reference to the argument (hence the name "pass-by-reference") is supplied into the AssignTo function. Thus, the assignment in AssignTo modifies not just the variable named param, but also the variable x in the caller, causing the output to be 5 and not 3.

Implicit Pointers

In some programming languages (such as Java, JavaScript, C#, etc.), parameters of an object type are implicitly pointers. This does not mean the parameter passing style is pass-by-reference. Pass-by-value and pass-by-reference can only be distinguished on the basis of assignment; both pass-by-value and pass-by-reference can both modify the supplied parameter (e.g. if the parameter is a pointer, the data that it points to may be modified by the function), but only pass-by-reference can change where the supplied pointer points (whereas pass-by-value cannot reassign the supplied pointer to point to a different address).

Pass-by-value-result

Pass-by-value-result is not commonly built into programming languages directly, but is frequently used in parallel programming. In pass-by-value-result, it is possible to assign to the parameter, but the assignment is delayed. That is, pass-by-value-result invokes the function in a manner similar to pass-by-value; however, at the very end, instead of discarding the copies of the variables, these copies are written back to the original arguments at the very end of the function (allowing tor assignments to affect the caller).

To make this more concrete, consider the following pseudo-code:

This is a scenario involving parameter "aliasing"; that is, one parameter actually references another parameter. In pass-by-reference, this aliasing causes the second statement to add a value of 2 rather than a value of 1, leading to a final result of 4. In pass-by-value-result, on the other hand, both statements add a value of 1, resulting in the code printing 3.

Pass-by-name

In most programming languages, passing an expression as an argument causes the expression to be evaluated, and then the result of that evaluation is passed as an argument to the function. In pass-by-name, rather than pass the result of evaluating the expression, the expression is passed literally to the function. Within the execution of the function, the use of the parameter is replaced by the expression that was provided. Pass-by-name can be thought of as a symbolic or textual substitution.

To make this more concrete, consider the following pseudo-code:

Under pass-by-value, this would be executed roughly as follows:

Under pass-by-name, however, this ends up getting executed roughly as follows:

In other words, pass-by-name substitutes the parameters, first, and only then evaluates; other parameter passing styles evaluate parameters first, and only then perform substitution and evaluation. The C and C++ preprocessor is an example of a real-world programming language mechanism that uses pass-by-name.

Conclusion

There are many different ways that programming languages can bind function parameters to the arguments at the point of invocation. Pass-by-value and pass-by-reference are common strategies, but others exist. Hopefully, at this point, you will feel comfortable knowing the difference between these techniques, how to create a simple test case for figuring out the parameter passing style of your favorite programming language, and how to ace your next programming language test.

Discover and read more posts from Michael Safyan
get started
Enjoy this post?

Leave a like and comment for Michael

Be the first to share your opinion

Subscribe to our weekly newsletter