Section 8.14. Passing Arrays: ByVal vs. ByRef


8.14. Passing Arrays: ByVal vs. ByRef

A variable that "stores" an object, such as an array, does not actually store the object itself. Instead, the variable stores a reference to the object (i.e., the address of the location in the computer's memory where the object is stored). Recall that in Chapters 46, we discussed two types of variablesvalue types and reference types. The distinction between value-type variables and reference-type variables raises some subtle issues that you must understand to create secure, stable programs.

Effects of ByVal on Value-Type Parameters and Reference-Type Parameters

When used to declare a value-type parameter, keyword ByVal causes the value of the argument to be copied to a local variable in the method. Changes to the local variable are reflected in the local copy of the variable, but not in the original variable in the calling program. If the argument passed using keyword ByVal is of a reference type, the value copied is a reference to the original object in the computer's memory. Thus, reference types (like arrays and other objects) passed via keyword ByVal are actually passed by reference, meaning that changes made to the objects in called methods are actually made to the original objects in the callers.

Performance Tip 8.1

Passing arrays and other objects by reference makes sense for performance reasons. If arrays were passed by value, a copy of each element would be passed. For large, frequently passed arrays, this would waste time and consume considerable storage for the copies of the arraysboth of these problems cause poor performance.


Passing Reference Type Parameters Using ByRef

Visual Basic also allows methods to pass references with keyword ByRef. This is a subtle capability, which, if misused, can lead to problems. For instance, when a reference-type object like an array is passed with ByRef, the called method actually gains control over the original reference in the caller, allowing the called method to replace the reference with one to a different object or even with Nothing. Such behavior can lead to unpredictable effects, which can be disastrous in business-critical and mission-critical applications. The program in Fig. 8.22 demonstrates the subtle difference between passing a reference ByVal and passing a reference ByRef.

Figure 8.22. Passing an array reference with ByVal and ByRef.

  1  ' Fig. 8.22: ArrayReferenceTest.vb  2  ' Testing the effects of passing array references using ByVal and ByRef.  3  Module ArrayReferenceTest  4     Sub Main()  5        ' declare array references  6        Dim firstArray As Integer()  7        Dim firstArrayCopy As Integer()  8  9       ' allocate firstArray and copy its reference 10       firstArray = New Integer() {1, 2, 3} 11       firstArrayCopy = firstArray ' reference preceding array 12 13       Console.WriteLine("Passing an array reference using ByVal.") 14       Console.Write("Contents of firstArray before calling FirstDouble: ") 15 16       ' print contents of firstArray 17        For i As Integer = 0 To firstArray.GetUpperBound(0) 18           Console.Write(firstArray(i) & " ") 19        Next 20 21        FirstDouble(firstArray) ' pass firstArray using ByVal 22        Console.Write(vbCrLf & "Contents of firstArray after " & _ 23           "calling FirstDouble: ") 24 25        ' print contents of firstArray 26        For i As Integer = 0 To firstArray.GetUpperBound(0) 27           Console.Write(firstArray(i) & " ") 28        Next 29 30        ' was reference to firstArray changed by FirstDouble? 31        If firstArray Is firstArrayCopy Then 32           Console.WriteLine(vbCrLf & "The references are equal.") 33        Else 34           Console.WriteLine(vbCrLf & "The references are not equal.") 35        End If 36 37        ' declare array references 38        Dim secondArray As Integer() 39        Dim secondArrayCopy As Integer() 40 41        ' allocate secondArray and copy its reference 42        secondArray = New Integer() {1, 2, 3} 43        secondArrayCopy = secondArray 44 45        Console.WriteLine(vbCrLf & "Passing an array " & _ 46           "reference using ByRef.") 47        Console.Write("Contents of secondArray before " & _ 48           "calling SecondDouble: ") 49 50        ' print contents of secondArray before method call 51        For i As Integer = 0 To secondArray.GetUpperBound(0) 52           Console.Write(secondArray(i) & " ") 53        Next 54 55        SecondDouble(secondArray) ' pass secondArray using ByRef 56        Console.Write(vbCrLf & "Contents of secondArray " & _  57           "after calling SecondDouble: ") 58 59        ' print contents of secondArray after method call 60        For i As Integer = 0 To secondArray.GetUpperBound(0) 61           Console.Write(secondArray(i) & " ") 62        Next 63 64        ' was reference secondArray changed by SecondDouble 65        If secondArray Is secondArrayCopy Then 66           Console.WriteLine(vbCrLf & "The references are equal.") 67        Else 68           Console.WriteLine(vbCrLf & "The references are not equal.") 69        End If 70     End Sub ' Main 71 72     ' method modifies elements of array and assigns 73     ' new reference (note ByVal) 74     Sub FirstDouble(ByVal array As Integer()) 75        ' double each element value in caller's array 76        For i As Integer = 0 To array.GetUpperBound(0) 77           array(i) *= 2 ' double the ith element 78        Next 79 80        ' create a new array and assign its reference to the variable array  81           array = New Integer() {11, 12, 13}                                82     End Sub ' FirstDouble 83 84     ' method modifies elements of array and assigns 85     ' new reference (note ByRef) 86     Sub SecondDouble(ByRef array As Integer()) 87        ' double each element value in caller's array 88        For i As Integer = 0 To array.GetUpperBound(0) 89           array(i) *= 2 ' double the ith element 90        Next 91 92        ' create a new array and assign its reference to the variable array  93        array = New Integer() {11, 12, 13} ' lose the 2, 4, 6 array          94     End Sub ' SecondDouble 95  End Module ' ArrayReferenceTest 

[View full width]

Passing an array reference using ByVal. Contents of firstArray before calling FirstDouble: 1 2 3 Contents of firstArray after calling FirstDouble: 2 4 6 The references are equal. Passing an array reference using ByRef. Contents of secondArray before calling SecondDouble: 1 2 3 Contents of secondArray after calling SecondDouble : 11 12 13 The references are not equal.



Lines 67 declare two Integer array variables, firstArray and firstArrayCopy (we make the copy so that we can determine whether the reference firstArray gets overwritten by method FirstDouble). Line 10 allocates an array containing Integer values 1, 2 and 3 and stores the array reference in variable firstArray. The assignment statement at line 11 copies the reference firstArray to the reference variable firstArrayCopy, causing these variables to reference the same array object. The For...Next statement in lines 1719 prints the contents of firstArray before it is passed to method FirstDouble at line 21 so we can verify that this array is passed by reference (i.e., the called method indeed changes the array's contents in Main).

The For...Next statement in method FirstDouble (lines 7678) multiplies the values of all the elements in the array by 2. Line 81 allocates a new array containing the values 11, 12 and 13; the reference for this array then is assigned to parameter array (in an attempt to overwrite reference firstArray in Mainthis, of course, does not happen, because the reference firstArray was passed ByVal). After method FirstDouble executes, the For...Next statement in lines 2628 prints the contents of firstArray, demonstrating that the values of the elements have been changed by the method FirstDouble (and confirming that in Visual Basic arrays are always passed by reference). The If statement in lines 3135 uses the Is operator to compare references firstArray (which we just attempted to overwrite) and firstArrayCopy. Visual Basic provides operator Is for comparing references to determine whether they are referencing the same object. The expression at line 31 is true if the operands to the binary operator Is reference the same object. In this case, the object represented is the array allocated in line 10not the array allocated in method FirstDouble (line 81). Visual Basic also provides operator IsNot for comparing two references. If two references refer to the same objects, operator IsNot returns False; otherwise it returns true. Line 81 modifies only the parameter array, not the variable firstArray because firstArray was passed with keyword ByVal. We will see in a moment the effect of passing an array with keyword ByRef.

Lines 3869 in method Main perform similar tests, using array variables secondArray and secondArrayCopy and method SecondDouble (lines 8694). Method SecondDouble performs the same operations as FirstDouble, but receives its array argument with ByRef. In this case, the reference stored in secondArray after the method call is a reference to the array allocated at line 93 of SecondDouble, demonstrating that a reference passed with ByRef can be modified by the called method so that the reference actually points to a different object, in this case the array that is allocated in method SecondDouble. The If statement in lines 6569 determines that secondArray and secondArrayCopy no longer represent the same array.

Software Engineering Observation 8.2

Using ByVal to receive a reference-type object parameter does not cause the object to pass by valuethe object still passes by reference. ByVal causes only the object's reference to pass by value. This prevents a called method from overwriting a reference in the caller. In the vast majority of cases, protecting the caller's reference from modification is the desired behavior. If you encounter a situation where you truly want the called method to modify the caller's reference, pass the reference-type object ByRef.




Visual BasicR 2005 for Programmers. DeitelR Developer Series
Visual Basic 2005 for Programmers (2nd Edition)
ISBN: 013225140X
EAN: 2147483647
Year: 2004
Pages: 435

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net