“Call by value” vs “Call by reference” in C# (bis)

The previous example is good to get you going, there are however some side notes here to make. When a reference type is called by value, it is actually taking a shallow copy of the variable you pass into the method. Almost like you’re doing this:
variable inside the method  = variable outside the method
So you have 2 objects pointing to the same data, and so it is normal that when you’re adjusting the data inside the method it also applies to the data outside of the method, because it is the same data in memory. However, if inside of your method you reassign the method variable to a different object, a new object or null, the changes you then make after reassigning will no longer affect to variable outside of the method, because we are simply no longer referring to it.

And that is where the difference relies for calling by reference for reference types. The variable inside the method is not a copy of the variable passed into the method, it is the same variable which implies that if you assign it to null, a new object or another object inside the method these changes are also applied for the outer method variable. And to illustrate this: a code example.

In the previous example, add these functions:

private static void SetInitialData(List<int> numbers)
{

numbers = new List<int>();
numbers.Add(10);
numbers.Add(11);
numbers.Add(12);

}

private static void SetInitialData(ref List<int> numbers)
{

numbers = new List<int>();
numbers.Add(10);
numbers.Add(11);
numbers.Add(12);

}

And in the Main function, add these statements:

Console.WriteLine (“\nReset called by value…”);
SetInitialData(numbers);
for (int i=0; i<numbers.Count; i++) Console.WriteLine (“numbers[“ + i + “] = “ + numbers[i]);

Console.WriteLine (“\nReset called by reference…”);
SetInitialData(ref numbers);
for (int i=0; i<numbers.Count; i++) Console.WriteLine (“numbers[“ + i + “] = “ + numbers[i]);

We now get the following output:

k = 1
numbers[0] = 10
numbers[1] = 11
numbers[2] = 12

Increment called by value…
k = 1
numbers[0] = 11
numbers[1] = 12
numbers[2] = 13

Increment called by reference…
k = 2
numbers[0] = 12
numbers[1] = 13
numbers[2] = 14

Add called by value…
numbers[0] = 12
numbers[1] = 13
numbers[2] = 14
numbers[3] = 20

Add called by reference…
numbers[0] = 12
numbers[1] = 13
numbers[2] = 14
numbers[3] = 20
numbers[4] = 25

Reset called by value…
numbers[0] = 12
numbers[1] = 13
numbers[2] = 14
numbers[3] = 20
numbers[4] = 25

Reset called by reference…
numbers[0] = 10
numbers[1] = 11
numbers[2] = 12

As you can see, in the call by value method we reassigned the method variable and thus changes to this variable no longer applied to the variable passed into the method. In the call by reference method changes do apply because we’re basically working with the same variable.

Another thing to add here: variables of the type struct may look like a stripped down version of a class, it is however different in a way that a struct is a value type  while a class is a reference type. In coding a struct may look like a reference object of a class, however in behavior it  acts like primitive types like int, bool, … So if you pass a struct into a method and call it by value, the variable in the method is a copy of the struct passed into the method, and so if you change the struct variable in the method the changes will not apply to the struct outside of the method (unless you return the changes). When calling by reference, you’re working with the same variable as outside the method and so changes inside the method do also apply outside the method.

Advertisements

“Call by value” vs “Call by reference” in C#

In this small example I hope to show you the differences in passing reference and value types in C# and what happens if you make the parameters either call by value or call by reference. All combinations are possible.

Reference vs Value variable types
In C#, as you know there are different variable types, for example int’s are value types and List<in> and other objects are reference types. It means that a variable of type int contains a value that you can adjust directly in memory, while for reference variables the variable itself is more or less just a referring to a spot in memory where all the object data is located and so the reference variable itself actually only contains a memory address.

“Call by reference” vs “Call by value”
As you may or may not know there are also different ways of passing parameters in C#. You can either call them by value, which is the default way of doing so, but you can also call them by reference. To do this one needs to explicitly add ‘ref’ both in the method signature and when calling this method.
What is the difference? When you pass the parameters by value, a copy is being taken of the data. When using referenced parameters only the reference to the data is passed.
But what does this imply? Well.. when ‘calling by value’  you get a copy of the variable and whatever you do inside the method does not affect the variable outside of this method (unless you use a return statement and reassign the variable with the returning data). Yet, if you ‘call by reference’ you have a reference to the place in memory where the variable relies, and so when you’re changing the variable inside the method it will also affect the variable outside of the scope of the method.

There are however side affects that you need to know off… because reference type variables actually contain just a reference to a space in memory, the variable itself is always passed in a call by reference way, and so when passing reference types you do not explicitly have to do a call by reference, but it is happening implicitly.

Here is an example that shows the difference:

class MainClass
{

public static void Main (string[] args)
{

int k = 1; //value type
List<int> numbers = new List<int>(); //reference type
numbers.Add(10);
numbers.Add(11);
numbers.Add(12);

//print default values
Console.WriteLine (“k = “ + k);
for (int i=0; i<numbers.Count; i++) Console.WriteLine (“numbers[“ + i + “] = “ + numbers[i]);

Console.WriteLine (“\nIncrement called by value…”);
Increment(k); //value type, call by value
Increment(numbers); //reference type, call by value
Console.WriteLine (“k = “ + k);
for (int i=0; i<numbers.Count; i++) Console.WriteLine (“numbers[“ + i + “] = “ + numbers[i]);

Console.WriteLine (“\nIncrement called by reference…”);
Increment(ref k); //value type, call by reference
Increment(ref numbers); //reference type, call by reference
Console.WriteLine (“k = “ + k);
for (int i=0; i<numbers.Count; i++) Console.WriteLine (“numbers[“ + i + “] = “ + numbers[i]);

Console.WriteLine (“\nAdd called by value…”);
Add(numbers);
for (int i=0; i<numbers.Count; i++) Console.WriteLine (“numbers[“ + i + “] = “ + numbers[i]);

Console.WriteLine (“\nAdd called by reference…”);
Add(ref numbers);
for (int i=0; i<numbers.Count; i++) Console.WriteLine (“numbers[“ + i + “] = + numbers[i]);

}

#region called by value
private static void Increment (int k)
{

k++;

}

private static void Increment (List<int> numbers)
{

for (int i=0; i<numbers.Count; i++) numbers[i]++;

}

private static void Add (List<int> numbers)
{

numbers.Add(20);

}
#endregion

#region called by reference
private static void Increment (ref int k)
{

k++;

}

private static void Increment (ref List<int> numbers)
{

for (int i=0; i<numbers.Count; i++) numbers[i]++;

}

private static void Add (ref List<int> numbers)
{

numbers.Add(20);

}
#endregion

}//end of class

Output:

k = 1
numbers[0] = 10
numbers[1] = 11
numbers[2] = 12

Increment called by value…
k = 1
numbers[0] = 11
numbers[1] = 12
numbers[2] = 13

Increment called by reference…
k = 2
numbers[0] = 12
numbers[1] = 13
numbers[2] = 14

Add called by value…
numbers[0] = 12
numbers[1] = 13
numbers[2] = 14
numbers[3] = 20

Add called by reference…
numbers[0] = 12
numbers[1] = 13
numbers[2] = 14
numbers[3] = 20
numbers[4] = 25

As you can see, variable types called by value don’t get adjusted out of the method, only when you call them by reference. For reference types, there is no difference on first sight in between calling by value or calling by reference because the variable itself is already a reference.

Note: I’m testing this C# code on a Linux machine using MonoDevelop. On a Windows system using .Net you will however get the same results.