Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This is a common question asked on nearly every forum I have seen, and the answer is simple:

Rule 1: When passing an Object (Reference Type) ByVal, a copy of the Object is passed.

Rule 2: A variable (Value Type) passed ByVal is not affected by the code inside the method, while a variable passed ByRef is.

Example 1: Value Types

To demonstrate, build and run this simple Console Application:

Public Module1

  Public Sub DoSomething(ByVal x As Integer, ByRef As Double)

    x += 5
    y += 5

    Console.WriteLine("Inside Method Call:")
    Console.WriteLine("num= {0}", x.ToString)
    Console.WriteLine("anum = {0}", y.ToString)

  End Sub

  Sub Main()
    Dim num As Integer = 5
    Dim anum As Double = 20.5

    Console.WriteLine("Before Method Call:")
    Console.WriteLine("num = {0}", num.ToString)
    Console.WriteLine("anum = {0}", anum.ToString)

    DoSomething(num, anum)

    Console.WriteLine("After Method Call:")
    Console.WriteLine("num = {0}", num.ToString)
    Console.WriteLine("anum = {0}", anum.ToString)

    Console.Read()

  End Sub
End Module

Result:

  Before Method Call:
  num = 5
  anum = 20.5

  Inside Method Call:
  num = 10
  anum = 25.5

  After Method Call:
  num = 5
  anum = 25.5

j0434929.png Note that in the code, we set two variables and initialize them:

Dim num as Integer = 5,
Dim anum as Double = 20.5

After displaying the initialized values, we call the method DoSomething(), supplying our variables as parameters. num is passed ByVal and anum is passed ByRef.

Check the results on your screen to see what has happened.

Because num was passed ByVal, no changes were made to the variable - a copy of the variable was passed into the method.

And, as anum was passed ByRef, any changes made in the method body will still be in effect after the method has completed.

Example 2 - Reference Types

Now that you have seen what happens when you pass value types ByVal and ByRef, let's see what happens when we pass Reference Types (objects).

Create a new console project:

Module Module1

    Class Person
        Private _name As String

        Public Property Name() As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
            End Set
        End Property

        Public Sub New(ByVal name As String)
            Me.Name = name
        End Sub

    End Class

    Public Sub DoSomething(ByVal person1 As Person, _
                           ByRef person2 As Person)

        person1.Name = "Changed Name"

        person2.Name = "Also Changed"

        Console.WriteLine("Inside Method:")
        Console.WriteLine("Person1 Name: {0}", person1.Name)
        Console.WriteLine("Person2 Name: {0}", person2.Name)
        Console.WriteLine()

	Person1 = Nothing
	Person2 = Nothing

    End Sub

    Sub Main()
        Dim p1 As New Person("Captain Cook")
        Dim p2 As New Person("Vasco da Gama")

        Console.WriteLine("Before Method Call:")
        Console.WriteLine("Person1 Name: {0}", p1.Name)
        Console.WriteLine("Person2 Name: {0}", p2.Name)
        Console.WriteLine()

        DoSomething(p1, p2)

        Console.WriteLine("After Method Call:")
        Console.WriteLine("Person1 Name: {0}", p1.Name)
        Console.WriteLine("Person2 Name: {0}", p2.Name)	' NullReferenceException

        Console.Read()

    End Sub

Result:

Before Method Call:
Person1 Name: Captain Cook
Person2 Name: Vasco da Gama

Inside Method:
Person1 Name: Changed Name
Person2 Name: Also Changed

After Method Call:
Person1 Name: Changed Name
' Error here

j0434929.pngWe passed two Person parameters to the method DoSomething():

Dim p1 As New Person("Captain Cook")
Dim p2 as New Person("Vasco da Gama")

In the call to the method, the first argument p1 is passed ByVal, while the second argument p2 is passed ByRef as in the first example.

However, as the results show, the ByVal declaration is ignored and a copy of the Person object p1 is passed.

An Additional Thought

The beauty of passing a value type ByRef is that you can in-effect make a Sub into a "Function without a declared Return Type", and return more than one value from a Function!

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralMy vote of 1
Jecka
1:03 16 Dec '09  
It contains a lot of wrong statements!
It should be erased from the Resource!
GeneralWhy is not this article erased from the Resource so far???
Jecka
1:00 16 Dec '09  
This article containts a lot of wrong things listed in previous comments so I should not repeat it!
Author should read books for beginners first before making articles about such a theoretic question
GeneralPlease the correct the article or just scrp it if possible.,. It will misleads the begginers.,.
Srinath G Nath
21:24 9 Dec '09  
The explanation you have given is not fully correct [inaccurate]. Please edit it.,.

Check out the links given below:

http://msdn.microsoft.com/en-us/library/ddck1z30%28VS.71%29.aspx[^]

ByVal[^]

ByRef[^]
GeneralPassing a reference ByRef is not the same as ByVal.
supercat9
8:23 2 Dec '09  
If an object reference is passed to a method by value, the method may make changes to the particular object identified by the reference, but it cannot change the fact that the reference points to that object. If an object reference is passed by reference, the method may change that object reference so it points to a different object.

Consider:

Sub Foo(ByRef A() As Byte)
A(0) = 1
Redim Preserve A(1)
Debug.Print(A(0))
A(0) = 2
End Sub
Sub Bar(ByVal A() As Byte)
A(0) = 3
Foo(A)
Debug.Print(A(0))
A(0) = 4
End Sub
Sub Boz()
Dim A(0) As Byte
A(0) = 5
Bar(A)
Debug.Print(A(0))
End Sub

Explain what is printed, and why.
GeneralThe only thing that should be ignored
TimMahy2003
12:34 1 Dec '09  
is your article:

However, as the results show, the ByVal declaration is ignored and the Person object p1 is treated as if ByRef.

Please, first learn the platform before you write articles.
GeneralInaccurate.
dequadin
8:33 29 Nov '09  
Rule 1 is false: "Rule 1: When passing an Object (Reference Type), the Object is always passed ByRef."

What you are trying to say is:
When a reference type is passed ByVal, a copy of the reference is passed to the method.

C# Code to explain, as I'm sure you know StringBuilder is a reference type.

class Program
{
static void ByValueExample(StringBuilder sb)
{
sb.AppendLine(" ByValueExample");
sb = null; // <- NB. This has no effect since we are working with a copy of the reference
}

static void ByReferenceExample(ref StringBuilder sb)
{
sb.AppendLine(" ByReferenceExample");
sb = null; // <- NB. This now has an effect since we are working with the actual reference
}

static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
sb.Append("Main Method");

Program.ByValueExample(sb);
System.Console.WriteLine(sb.ToString()); // Output "Main Method ByValueExample" to the Console as expected

Program.ByReferenceExample(ref sb);
System.Console.WriteLine(sb.ToString()); // NullReferenceException
}
}


Please read this article on parameter passing in .NET, the same concept applies to Visual Basic.NET
GeneralRe: Inaccurate.
Andy_L_J
19:11 29 Nov '09  
You are 100% correct, the error being overlooked in my haste.

I will edit the article and add the null reference test in VB (citing this post).

Thanks for the heads up - sometimes I can't see the woods for the trees Red faced

I don't speak Idiot - please talk slowly and clearly

'This space for rent'

Driven to the arms of Heineken by the wife

GeneralRe: Inaccurate.
dequadin
3:06 30 Nov '09  
No problem, these more beginner orientated (myself included) need to have the fundamentals 100% correct otherwise they can be misleading to someone who doesn't know better.

I think the crux here is the distinction whereby if you pass a reference type by value a copy of the reference is passed and not a copy of the object, as is the case in some other languages.

You can also get some "unexpected" behavior with the new keyword.
class Program
{
static void ByValueExample(StringBuilder sb)
{
sb.AppendLine(" ByValueExample");
sb = new StringBuilder(); // <- NB. This has no effect since we are working with a copy of the reference
sb.AppendLine("New object here :)");
}

static void ByReferenceExample(ref StringBuilder sb)
{
sb.AppendLine(" ByReferenceExample");
sb = new StringBuilder(); // <- NB. This now has an effect since we are working with the actual reference
sb.AppendLine("New object here :)");
}

static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
sb.Append("Main Method");

Program.ByValueExample(sb);
System.Console.WriteLine(sb.ToString()); // Output "Main Method ByValueExample", possibly unexpected?

Program.ByReferenceExample(ref sb);
System.Console.WriteLine(sb.ToString()); // Output: "New object here :)"
}
}


Rather reference that article by Jon Skeet (in my previous post), that's where I got my understanding on this from. He's a much more authoritative source than I Smile


Last Updated 2 Dec 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010