Skip to main content

Command Palette

Search for a command to run...

Call by Value vs Call by Reference: The TRUTH

Published
5 min read
Call by Value vs Call by Reference: The TRUTH
T
I focus on clean architecture, performance optimization, and designing systems that are maintainable and resilient.

Call by Value vs Call by Reference: The TRUTH

🎥 Watch the original video on YouTube: Click here to watch


Call by Value vs Call by Reference: The Complete Guide

When working with .NET and C#, one of the most fundamental concepts every developer must understand is the difference between call by value and call by reference. These mechanisms determine how data is passed between variables and functions, directly affecting how your code behaves and manages memory. Whether you're working with value types like integers and characters, or reference types like classes, strings, and interfaces, understanding these calling conventions is essential for writing efficient and bug-free code.

Understanding Call by Value

What is Call by Value?

By default, C# uses call by value when passing parameters to methods. This means that when you assign a variable's value to another variable, or pass it as a parameter, only the actual value is copied—not the memory address of the original variable.

How Call by Value Works

Let's consider a simple example:

int a = 15;
int b = a;
b = 30;

Console.WriteLine($"a = {a}, b = {b}");
// Output: a = 15, b = 30

In this scenario, when you assign a to b, the value 15 is copied into a separate memory location. When you later modify b to 30, the original variable a remains unchanged at 15.

Memory Allocation in Call by Value

When you create a variable with a value type:

  1. Memory is allocated on the stack
  2. The actual value is stored at that memory address
  3. When you assign this variable to another, the runtime copies the value, not the reference
  4. Each variable occupies its own distinct memory location
  5. Changes to one variable never affect the other

This behavior is true for all value types in C#, including int, double, char, bool, and struct.

Call by Value with Methods

Even when passing value types through methods, the same principle applies:

public void UpdateValue(int number)
{
    number = 50;
}

int myNumber = 15;
UpdateValue(myNumber);
Console.WriteLine(myNumber);
// Output: 15

The method receives a copy of the value, so any modifications inside the method don't affect the original variable.

Understanding Call by Reference

What is Call by Reference?

Call by reference means that multiple variables can point to the same memory location. This is the behavior of reference types in C#, such as classes, interfaces, delegates, and strings. When you assign a reference type variable to another, you're copying the memory address, not the data itself.

Reference Types vs Value Types

The key difference between reference and value types is where they're stored:

  • Value types: Stored on the stack
  • Reference types: The object data is stored on the heap, while the reference (memory address) is stored on the stack

How Call by Reference Works

Consider this example with a class:

public class Employee
{
    public string Name { get; set; }
}

Employee emp1 = new Employee { Name = "John" };
Employee emp2 = emp1;
emp2.Name = "James";

Console.WriteLine($"emp1.Name = {emp1.Name}, emp2.Name = {emp2.Name}");
// Output: emp1.Name = James, emp2.Name = James

Here's what happens in memory:

  1. An Employee object is created on the heap with the name "John"
  2. The stack contains emp1 (a reference variable) pointing to this heap object
  3. When you assign emp1 to emp2, you're copying the memory address, not the object itself
  4. Both emp1 and emp2 now point to the same object on the heap
  5. Any changes made through either reference affect the same underlying object

Memory Diagram for Reference Types

Stack Memory:
emp1 → Address: 0x10010 ┐
emp2 → Address: 0x10010 ┤
                        ├─→ Heap Memory
                        │   Employee Object
                        │   { Name = "James" }

Both variables hold the same heap address, so they reference the same object.

Reference Types in Method Parameters

The Challenge with Methods

A common misconception is that you can modify a reference type inside a method and have those changes persist. Let's examine what actually happens:

public void UpdateEmployee(Employee emp)
{
    emp.Name = "Updated";
}

Employee employee1 = new Employee { Name = "Original" };
UpdateEmployee(employee1);
Console.WriteLine(employee1.Name);
// Output: Updated

In this case, the property change works because both variables reference the same object. However, what if you try to reassign the reference itself?

public void ReplaceEmployee(Employee emp)
{
    emp = new Employee { Name = "NewEmployee" };
}

Employee employee1 = new Employee { Name = "Original" };
ReplaceEmployee(employee1);
Console.WriteLine(employee1.Name);
// Output: Original

The reassignment inside the method creates a new object on the heap and makes the local variable emp point to it. The original variable employee1 remains unchanged because the method received a copy of the reference, not the reference itself.

Using the 'ref' Keyword

To truly pass by reference and allow method parameters to be reassigned, use the ref keyword:

public void ReplaceEmployee(ref Employee emp)
{
    emp = new Employee { Name = "NewEmployee" };
}

Employee employee1 = new Employee { Name = "Original" };
ReplaceEmployee(ref employee1);
Console.WriteLine(employee1.Name);
// Output: NewEmployee

With the ref keyword, the method receives the actual reference variable, not a copy, allowing reassignments to affect the original variable.

Key Takeaways

  • Call by Value is the default: Whether using value types or reference types, C# passes copies of values by default
  • Value types store data on the stack: Changes to one variable don't affect copies of that variable
  • Reference types store objects on the heap: Multiple references can point to the same object, so changes via any reference are visible to all references
  • Reference type reassignments inside methods don't persist: Unless you use the ref keyword
  • Use ref for true pass-by-reference behavior: When you need a method to reassign a reference variable and have that change reflected in the caller's scope

Conclusion

Understanding call by value versus call by reference is crucial for writing correct and efficient C# code. By default, everything in C# uses call by value semantics—whether it's copying an integer or copying a reference to an object. The difference lies in what's being copied: the actual data for value types, or the memory address for reference types. Mastery of these concepts will help you avoid subtle bugs and write more predictable code.