Demystifying Function Calls: The 5 Parameter-Passing Mechanisms in Programming Languages With Analogies

Kerron Parchment
5 min readMar 21, 2023

--

Photo by James Harrison on Unsplash

Parameter-passing mechanisms define how arguments are passed from a calling function to a called function in programming languages. Understanding these mechanisms is crucial for developers to write efficient and predictable code. In this article, we will explore the five main parameter-passing mechanisms with examples in appropriate programming languages and compare their characteristics.

1. Call-by-value

In call-by-value, the value of the argument is passed to the called function, and any changes made to the parameter inside the function do not affect the original variable. This is because the called function receives a copy of the argument value. Call-by-value is widely used in languages like C, Java, and most functional programming languages.

Analogy — The Photocopy: Think of call-by-value as handing someone a photocopy of a document. Any changes they make to the photocopy don’t affect the original document. This is how call-by-value works in programming languages like C and Java: the called function receives a copy of the argument value, so any changes made to the parameter inside the function do not affect the original variable.

Example in C

Pros:

  • Prevents unintentional modifications to the original variable.
  • Simplifies reasoning about the function behaviour.

Cons:

  • May lead to performance overhead due to copying large data structures.

2. Call-by-reference

Call-by-reference passes the memory address of the argument to the called function. This allows the function to modify the original variable directly. Languages like C++, Fortran, and C# support call-by-reference. In C#, the ref keyword is used to explicitly indicate call-by-reference.

Analogy — The Shared Book: Call-by-reference can be thought of as giving someone access to your shared book with notes. Any notes they take will be visible to both of you, as you both have access to the same book. In programming languages like C++ and C#, the called function has access to the memory address of the argument, allowing it to modify the original variable directly.

Example in C++

Pros:

  • Efficient when working with large data structures.
  • Allows for multiple return values through function parameters.

Cons:

  • Can lead to unintended side effects due to direct modification of the original variable.

3. Call-by-name

Call-by-name is a mechanism where the expression passed as a parameter is substituted directly into the function body. It is a rare mechanism in modern programming languages but is supported by languages like Scala with the => (arrow) notation. Call-by-name enables lazy evaluation, which means that the expression is only evaluated when it is actually used inside the function.

Analogy — The Recipe: Call-by-name can be compared to a recipe. Instead of passing the prepared dish (value) to someone, you pass the recipe (expression). The recipe is then “cooked” (evaluated) each time it’s needed in the function. Languages like Scala support call-by-name, enabling lazy evaluation where expressions are evaluated only when used.

Example in Scala

Pros:

  • Can improve performance by avoiding unnecessary evaluations.
  • Enables interesting language constructs and control structures.

Cons:

  • Might lead to code that is harder to reason about due to multiple evaluations of the same expression.

4. Call-by-sharing (Call-by-object)

Call-by-sharing, also known as call-by-object or call-by-object-sharing, is a mechanism where a reference to the object is passed to the function. However, the reference itself is passed by value. This allows the function to modify the original object but not the reference. This mechanism is used in languages like Python, JavaScript, and Ruby.

Analogy — The House Key: Call-by-sharing is like giving someone a copy of your house key. They can enter your house and rearrange the furniture (modify object properties) but cannot change the house itself (the reference). Languages like Python, JavaScript, and Ruby use call-by-sharing, where the reference to the object is passed to the function but the reference itself is passed by value.

Example in Python

Pros:

  • Efficient when working with large data structures.
  • Provides a balance between call-by-value and call-by-reference in terms of safety and performance.

Cons:

  • Can still lead to unintended side effects due to modification of the original object.

5. Call-by-need (Lazy evaluation)

Call-by-need, also known as lazy evaluation, is a mechanism where function arguments are not evaluated until they are actually needed (used) inside the function. This can be beneficial for performance in certain situations, as it avoids unnecessary computation. Haskell is an example of a language that employs call-by-need evaluation.

Analogy — The On-Demand Chef : Call-by-need is like having an on-demand chef at your disposal. They prepare and cook a dish only when you’re ready to eat it. In programming languages like Haskell, function arguments are not evaluated until they are actually needed (used) inside the function. This lazy evaluation can be beneficial for performance, as it avoids unnecessary computation.

Example in Haskell

Pros:

  • Can improve performance by avoiding unnecessary evaluations.
  • Supports infinite data structures and other advanced constructs.

Cons:

  • May lead to increased memory usage due to unevaluated expressions.

Conclusion

Understanding the various parameter-passing mechanisms used in programming languages helps developers write more efficient and predictable code. By exploring these concepts through everyday analogies, you can grasp the key differences and characteristics more intuitively. As you continue your programming journey, keep these analogies in mind to help you make more informed decisions when designing and implementing your software.

--

--