Previous section   Next section

5.11 Passing Parameters by Value and by Reference

Visual Basic .NET differentiates between value types and reference types. All the intrinsic types (Integer, Long, etc.), as well as structures (described in Chapter 7) are value types. Classes are reference types, as are interfaces (described in Chapter 8).

By default, value types are passed into methods by value. This means that when a value object is passed to a method, a temporary copy of the object is created within that method. Once the method completes, the copy is discarded.

When you pass a reference type to a method a copy is made of the reference as well. The key difference is that the original reference and its copy both refer to the same actual object (on the heap). Changes you make through the copy of the reference are reflected back in the calling method. Thus, even though you are passing a copy of the reference you are "passing by reference"—that is, you are giving the method you are calling a reference to the actual object which it can modify.

Although passing by value is the normal case, there are times when you will want to pass value objects by reference. Visual Basic .NET allows you to make your intention explicit by using either the ByVal keyword or the ByRef keyword, as explained in the following sections.

5.11.1 Passing Parameters by Value

In many of the method calls shown in the previous sections, the parameters were marked with the keyword ByVal. This indicates that the arguments are passed to the method by value; that is, a copy of the argument is passed to the method. Examine the code in Example 5-11. Try to guess what the output will be before reading further.

Example 5-11. Using the ByVal parameter
Option Strict On
Imports System

Public Class Tester

   Public Sub Run( )
      ' declare a variable and initialize to 5
      Dim theVariable As Integer = 5

      ' display its value
      Console.WriteLine("In Run. theVariable: {0}", _
      theVariable)

      ' call a method and pass in the variable
      Doubler(theVariable)

      ' return and display the value again
      Console.WriteLine("Back in Run. theVariable: {0}", _
      theVariable)

   End Sub

   Public Sub Doubler(ByVal param As Integer)

      ' display the value that was passed in
      Console.WriteLine("In Method1. Received param: {0}", _
      param)

      'Double the value
      param *= 2

      ' Display the doubled value before returning
      Console.WriteLine( _
      "Updated param. Returning new value: {0}", _
      param)

   End Sub

End Class 'Tester


Module Module1

   Sub Main( )
      Dim t As New Tester( )
      t.Run( )
   End Sub

End Module

In Example 5-11, the Main( ) method does nothing but instantiate a Tester object and call Run( ). In Run( ), you create a local variable, theVariable, and initialize its value to 5, which you then display:

Dim theVariable As Integer = 5
Console.WriteLine("In Run. theVariable: {0}", _
theVariable)

You pass theVariable to the Doubler( ) method, which displays the value, doubles it, and then redisplays it before returning:

Public Sub Doubler(ByVal param As Integer)

   Console.WriteLine("In Method1. Received param: {0}", _
   param)

   param *= 2

   Console.WriteLine( _
   "Updated param. Returning new value: {0}", _
   param)

End Sub

When you return from the call to Doubler( ), you display the value of theVariable again. What is the value that is now displayed?

Console.WriteLine("Back in Run. theVariable: {0}", _
theVariable)

As shown in the output, the value of the variable that was passed in to Doubler( ) is, in fact, doubled in the Doubler( ) method, but is unchanged in the calling method (Run):

Output:
In Run. theVariable: 5
In Method1. Received param: 5
Updated param. Returning new value: 10
Back in Run. theVariable: 5

The value of the parameter was passed by value, and thus a copy was made in the Doubler( ) method. This copy was doubled, but the original value was unaffected.

5.11.2 Passing Parameters by Reference

Visual Basic .NET also supports passing parameters by reference using the ByRef keyword. You can test this by making one tiny change to Example 5-11, changing the parameter of Doubler( ) from ByVal to ByRef:

Public Sub Doubler(ByRef param As Integer)

The rest of the program remains completely unchanged. Run the program again and compare the new output with the original:

Output:
In Run. theVariable: 5
In Method1. Received param: 5
Updated param. Returning new value: 10
Back in Run. theVariable: 10

The value of the argument to the method is now passed by reference. That is, rather than a copy being made, a reference to the object itself is passed, as illustrated in Figure 5-6. The object referred to by param is now the variable declared in Run( ). Thus, when you change it in Doubler( ), the change is reflected back in the Run( ) method.

Figure 5-6. Passing arguments by reference
figs/pvn2_0506.gif

5.11.3 Passing Reference Types by Value

Earlier, you saw how you can create a copy of a reference to an object and then have the two references refer to the same object. Similarly, when you pass a reference as a parameter, a copy of the parameter is made, but that is a copy of a reference, and the two references refer to the same object. You can see the effect by modifying Example 5-11 to pass an object, rather than an Integer, by value. The complete listing is shown in Example 5-12. Analysis follows the output.

Example 5-12. Passing a reference as a parameter
Option Strict On
Imports System

Public Class Cat

   Private mWeight As Integer

   Public Sub New(ByVal weight As Integer)
      mWeight = weight
   End Sub

   Public Property Weight( ) As Integer
      Get
         Return mWeight
      End Get
      Set(ByVal Value As Integer)
         mWeight = Value
      End Set
   End Property

   Public Overrides Function ToString( ) As String
      Return mWeight.ToString( )
   End Function

End Class

Public Class Tester

   Public Sub Run( )
      'declare a Cat and initialize to 5
      Dim theVariable As New Cat(5)

      'display its value
      Console.WriteLine("In Run. theVariable: {0}", _
      theVariable)

      'call a method and pass in the variable
      Doubler(theVariable)

      'return and display the value again
      Console.WriteLine("Back in Run. theVariable: {0}", _
      theVariable)

   End Sub

   Public Sub Doubler(ByVal param As Cat)
      'display the value that was passed in
      Console.WriteLine("In Method1. Received param: {0}", _
      param)

      'double the value
      param.Weight = param.Weight * 2

      'display the doubled value before returning
      Console.WriteLine( _
      "Updated param. Returning new value: {0}", _
      param)

   End Sub

End Class 'Tester


Module Module1

   Sub Main( )
      Dim t As New Tester( )
      t.Run( )
   End Sub

End Module

Output:
In Run. theVariable: 5
In Method1. Received param: 5
Updated param. Returning new value: 10
Back in Run. theVariable: 10

Example 5-12 begins by defining a very simple Cat class:

Public Class Cat

The class has a single private member variable, mWeight, and a property (Weight) to get and set the value of that variable:

Private mWeight As Integer

Public Property Weight( ) As Integer
   Get
      Return mWeight
   End Get
   Set(ByVal Value As Integer)
      mWeight = Value
   End Set
End Property

The constructor allows you to initialize a Cat object by passing in an integer value for its weight:

Public Sub New(ByVal weight As Integer)
   mWeight = weight
End Sub

Finally, you override the ToString( ) method so that when you display the Cat object, its weight is displayed:

Public Overrides Function ToString( ) As String
   Return mWeight.ToString( )
End Function

Example 5-12 changes Example 5-11 as little as possible. The Run( ) method still creates a local object named theVariable, but this time it is a Cat rather than an integer:

Dim theVariable As New Cat(5)

The value of theVariable is displayed and then passed to the Doubler( ) method:

Console.WriteLine("In Run. theVariable: {0}", _
theVariable)
Doubler(theVariable)

In Example 5-12, the Doubler( ) method is changed to make the parameter be a Cat rather than an integer. Note that the parameter is marked ByVal. The Cat reference will be passed by value, and a copy of the reference will be made:

Public Sub Doubler(ByVal param As Cat)

Within Doubler( ), the value of the parameter is displayed, doubled, and then displayed again:

Console.WriteLine("In Method1. Received param: {0}
param)

param.Weight = param.Weight * 2

Console.WriteLine( _
"Updated param. Returning new value: {0}", _
param)

Back in Run( ), the value of theVariable is displayed:

Console.WriteLine("Back in Run. theVariable: {0}", _
theVariable)

This is identical to Example 5-11 in which the integer value of theVariable was unchanged after returning from Doubler( ). This time, however, the value is changed, even though the object was passed by value. The difference is that integers are value types, and classes are reference types.


  Previous section   Next section
Top