MichaelDev
Thursday, February 17, 2005
  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
 
Various notes on software development. Currently using C# and .Net. May also include comments on the overall software development process, etc.

Name:
Location: Orange County, California, United States
ARCHIVES
June 2004 / July 2004 / August 2004 / September 2004 / October 2004 / November 2004 / December 2004 / January 2005 / February 2005 / March 2005 / April 2005 / May 2005 / September 2005 / October 2005 / November 2005 / January 2006 / February 2006 / April 2006 / May 2006 / June 2006 / March 2007 /


Powered by Blogger