Is this title confusing ? I must admit thought a lot about what should be the title of this blogpost and could not come up with better than this one. Do you think that reference types are always passed by reference ? This article discusses this question and tries to highlight some interesting facts.
So, what is it about ?
This is one of my favorite topic since I have learnt C#. Let’s talk about why this question came to my mind.
We all know that there are two main categories of types – value types and reference types.
- A value type variable contains instance of the value. On the other hand, a reference type variable contains a reference to an instance of that type.
- Also, when a value type variable is assigned to another variable of same value type, the value is copied to the new variable. It means, two memory locations containing same values, hence changing value in first variable does not affect the other variable’s value. On the other hand, when a reference type variable is assigned to another variable of same type, the reference to the instance is copied. It means if some properties from the instance of reference type are modified using first variable and second variable is used to read the values from the instance, the modifications can still be seen, because underlying instance was same.
The two differences listed above are really important for today’s discussion. The discussion is about passing arguments to a method. In rest of the article, we are going to talk about how reference types are passed as arguments to the methods.
Value Types as Arguments
I think discussion in this section is quite obvious. But still putting it here for the sake of completeness of discussion.
TLDR; Value types are
passed by value to the called method, means modifications done in called method are not retained. Value types can also be
passed by reference by using ref or out keywords.
When a value type is passed as argument to a method, its value is copied over. It means another copy of the instance is created. This means if passed value is modified inside the called method, those changes would not reflect in the variable used in caller.
But in some cases, we may want the modifications back in the caller method. For such cases, we can use either
out keywords with parameters.
ref keyword is to pass reference to the instance of passed parameter. It can be used to pass a value and get the modified value in the same variable which was used to pass the argument to the method.
out keyword also passes reference to the instance of passed parameter. It is one way to get more than one return values from the called method.
Main difference between
out keyword is – in the called method, the parameter with out keyword is mandatorily required to be set to a value before returning from the method. If out parameter is not assigned with any value in the called method, it would cause a compile time error.
Below is a code example and its output explaining how value types can be passed as arguments – with and without ref keyword. It also shows output of the methods to prove that modified value comes back to the argument only if ref is used.
The code should show an output as shown in below snapshot:
Reference Types as Arguments
Now, this is where the fun begins !
We have already stated that a variable of reference type always holds a reference to an instance of that reference type.
That also means – if a reference type is passed as arguments, a reference to the instance is passed. So the called method gets a reference which points to original instance of the type. That also means, if I make any modifications to the original object, they would be still available in the caller method.
Below is a code example that shows how the caller method still gets the modified values even though the called function modified them. Note that we have not used
ref keyword here.
The snapshot below shows output from the code. So the modifications done by called method are available in the caller.
Does this mean that reference types are by default passed by reference ? If yes then, would we ever need to use
ref keyword with a parameter of reference type ?
A bit of play around
We already have seen that if some properties of an existing object are changed inside called method, the modifications are still available in the caller. It means that reference types are always passed by reference. But to confirm this, let’s go for an experiment.
This time the called method would create new instance instead of using the passed instance. If the argument is truly being passed as reference, the new object should be available for the caller. Below is the new modified code from
ReferenceTypeDemo class. Rest of the code is same as shown in previous code snippet.
Below is the output of the code. It shows that the new object created inside called method is not available to the caller. What does this mean ? Does this mean that reference types are not passed by reference?
So, What did exactly happen here ?
Let’s try to understand why new object created inside called method was not available to the caller.
Below snapshot shows conceptual representation of what happened. When ChangeObject method was called, both caller method and called methods were pointing to same object.
Next, when called method created new object, the variable from called method was pointing to a new memory location.
When the execution flow returned from called method, all the variables (including parameters) were released by the process, without really changing the value of original variable in caller method.
It means the reference to actual object (E6 in the snapshot below) was copied to a new location, as if it was an integer value. Because of this, the original variable from caller method stayed unaffected when a new object was created inside called method.
Reference Type – Pass by reference
By now, you have got the idea that without using ref keyword, reference types are “passed by value” – because their references are copied from one place to other.
What if a code needs to pass a reference type variable by reference ? The solution is simple – use
ref keyword. Below is a code example which shows a sample code and its output.
The output of above code is shown below. As you can see, the object created inside the called method is available to the caller too.
Like value types, reference types can also be passed to the called methods by two ways – by value and by reference.
When a reference type is passed by reference by using
ref keyword, it is truly passed as reference. The called method can either change existing properties or it can create a new object. In both cases, caller method can access the modifications.
Thus, ref keyword is the only way to truly pass any type as reference. It is not very common to use ref keyword with reference types, at least I have not seen it or used it very frequently. But, you should always be aware of the basics, so that you can use the language more effectively.
I hope you find this information helpful. Have you also done some similar experiments ? Let me know by commenting here on the post. You can also connect with me on twitter for conversations.