ByVal, ByRef
I'm working at a new place now. We're using VB.Net, so future examples will probably be in that language.
Someone at work did a nice little writeup on ByVal and ByRef in .Net. Thought I'd publish it here (hopefully he doesn't mind):
ByVal & ByRef…
Value type and Reference types…
.Net makes it all so clear.
Take the following examples:
Sub Main()
Dim MyInt As Integer = 10
ConvertInteger(MyInt)
Console.WriteLine(MyInt)
End Sub
Private Sub ConvertInteger(ByVal i As Integer)
i = i * 10
End Sub
What is the expected output?
We know ByVal tells makes a copy of the variable for value types therefore a new value will be created on the stack and the original value will not be changed.
Output:10
What about Strings?
Sub Main()
Dim MyString As String = "Mr. Piccolo"
ConvertString(MyString)
Console.WriteLine(MyString)
End Sub
Private Sub ConvertString(ByVal i As String)
i = String.Concat("HELLO ",i)
End Sub
What is the expected output?
We know that ByVal tells me that I make a copy, but String is a Reference type. Will it act the same?
Output: Mr. Piccolo
So Byval of a Reference type makes a copy just like a value type…right? RIGHT?!?!? L (No)
What if I wrap a String inside of a custom object and pass that ByVal?
Public Class Person
Private _Name As String = String.Empty
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal Value As String)
_Name = Value
End Set
End Property
End Class
Private Sub ConvertPerson(ByVal x As Person)
x.Name = "Virgil"
End Sub
Sub Main()
Dim MyPerson As New Person
MyPerson.Name = "Dante"
ConvertPerson(MyPerson)
Console.WriteLine(MyPerson.Name)
End Sub
I am passing a custom object ByVal and the object is a Reference type, it should come out as ‘Dante’…Right?
Output: Virgl
Why Virgil?
Person and String are both reference types and should abide by the same rules, correct?
No.
String is the exception, not the rule. A String is called immutable because its value cannot be modified once it has been created. Methods that appear to modify a String actually return a new String containing the modification.
Passing a Value type ByVal creates a new temporary variable on the stack with the value of the incoming parameter. Modifying this value will NOT alter the original.
Passing a Value type ByRef passes a pointer to the original variable. Modifying this value WILL alter the original.
Passing a Reference type ByVal does *NOT* create a clone of the original. It creates a COPY of the POINTER to the object on the Heap.
Passing a Reference type ByRef passes the POINTER to the object on the Heap.
Passing a String ByVal does *NOT* create a close of the original. It creates a COPY of the POINTER to the object on the Heap. However, once you modify the string, a new temporary string is created. Modifying this value will not alter the original.
Passing a String ByRef passes the POINTER to the object on the Heap. Modifying this value will alter the original.
So what’s the functional difference between passing an integer and a string ByVal to a method that alters the value? Nothing. Neither object can be modified by the method.
Why did Microsoft choose to implement ByVal Reference types this way? Why not create a copy of a Reference type when passed ByVal?
In order to accomplish this, the compiler would be required to copy not only the object on the heap, but any other objects it references or contains. This type of copy is often referred to as a “deep copy” or “clone”. The implementation Microsoft chose makes sense, if you think about the potential performance implications of doing a deep copy. Deep copies could end up allocating lots of memory on the heap, and this memory only gets cleaned up when the garbage collector gets around to it.
In summation:
A String is a .NET object that is a reference type that has value type semantics.
Since .NET strings are reference types, only a pointer value is pushed on the stack, whether you use ByRef or ByVal.
There is no obvious performance difference between passing Reference types ByVal or ByRef. (I believe ByVal is slightly faster)
One other interesting note…
An Interface is a reference type, even if defined in a Structure. The structure itself is a value type, however if you assign the structure to an Interface variable, it will be Boxed. Boxing places the value on the heap in a new object (effectively making it a reference type). J