Re: VB-101: Passing Arrays ByVal vs ByRef
- From: John Pass <JohnPass@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Tue, 24 May 2005 10:02:08 -0700
Ralf,
I very much appreciate your detailed explanation and I think I now
understand it (better), but it also opens new questions.
As I wrote originally, I already did understand that the Ref type parameter,
if passed ByVal, does not change the original array data in memory, because
it only points to and changes the value of an (other) instance of the same
array. My question was about why the change made in the 1st part of the sub
firstDouble (ByVal ...) made an effective change to the output printed to
screen, while the changes made in the 2nd part of the same sub had no effect.
I understand from your explanation that the code in the 2nd part of this sub
('array = New array() {11, 12, 13}' creates a completely new object. If that
is indeed the case, I would fully understand it!
But that would mean that there would be two different array objects with the
exact same name 'array', containing the same data of the same data type. That
sounds odd. How would the software be able to distinguish between the two?
New question triggered by your explanation:
You state that by using the code:
Dim firstArray As Integer()
Dim firstArrayCopy As Integer()
"an (one?) array object is created on the heap with two references".
Thus far I understood that this code would create two array objects with
identical content but different names for firstArray and firstArrayCopy, but
that the array 'array' as used in the procedures FirstDouble() and
SecondDouble() would be a reference to firstArray and not a new object. If
indeed one object with two refernces is created, for firstArray and
firstArrayCopy followed by a change of the array values, could it still be
one object with two instances? So far I cannot see how that is possible.
Thanks for you explanation,
John
"_AnonCoward" wrote:
>
>
> "John Pass" <JohnPass@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
> news:F694915A-595C-43B4-B89F-133516ED21F0@xxxxxxxxxxxxxxxx
> :
> : Hi,
> : In the attached example, I do understand that the references are not
> : changed if an array is passed by Val. What I do not understand is the
> : result of line 99 (If one can find this by line number) which is the
> : last line of the following sub routine:
> :
> : ' procedure modifies elements of array and assigns
> : ' new reference (note ByVal)
> : Sub FirstDouble(ByVal array As Integer())
> : Dim i As Integer
> :
> : ' double each element value
> : For i = 0 To array.GetUpperBound(0)
> : array(i) *= 2
> : Next
> :
> : ' create new reference and assign it to array
> : array = New Integer() {11, 12, 13}
> : End Sub ' FirstDouble
> :
> : Since the line where the values of the array 'array' are filled by the
> : values 11, 12 and 13 is the later part of the same sub-routine where
> : the earlier changes of values in the same array took place, I would
> : expect these values to be printed to the screen as output. To me, it
> : looks like the array values being returned to the calling function
> : were first doubled and that simply overwritten. Apparently this does
> : not happen.
> :
> : Can anyone explain why this happens?
> : (The complete example is attached below
> :
> : Thanks for your help,
> :
> : John
>
>
> I'm going to state up front that I'm not entirely certain if my
> understanding of this is correct (altho' I believe it is or I wouldn't
> offer this post), so take this provisionally.
>
>
> When you pass a reference type as a parameter into a function call, you
> are passing in a reference to the memory location of that object on the
> heap. The value that is passed in parameter 'array' in functions
> firstDouble and secondDouble are referneces to an instance of the array
> object on the heap. Consequently, those functions can modify the data in
> the array since they have a memory pointer to it.
>
>
> In each function call, a new integer array is instantiated and assigned
> to variable 'array'. These arrays are also on the heap and anything
> method that has a reference to those objects can modify them.
>
>
> As you are aware, the key difference between the two functions is that
> firstDouble accepts the array parameter 'ByVal' whereas the secondDouble
> accepts the array 'ByRef'. That (as I'm also sure you are aware) is the
> key to the different behaviors.
>
>
> As each function creates a new array object, the reference to which is
> then assigned to variable array. However, since parameter array is
> passed to function firstDouble 'ByVal', that new reference value is
> discarded when the function returns and variable firstArray still
> references the original array object on the heap. When secondDouble
> returns however, the reference to the new integer array is assigned to
> variable firstArray instead.
>
>
> I'm not sure if that is any clearer, so let me try another approach.
> When you reach this point in your code:
>
> firstArray = New Integer() {1, 2, 3}
> firstArrayCopy = firstArray
>
>
> an array object is created on the heap with two references: 'firstArray'
> and 'firstArrayCopy'. Both references are just pointers to the same
> memory location where the array object resides on the heap.
>
>
> When function 'firstDouble' is initially called, a *copy* of reference
> 'firstArray' is passed to the function on the stack (the object itself
> is not added to the stack, but the parameter that references it is). Now
> there are *3* references to a single object: 'firstArray',
> 'firstArrayCopy' (local to sub 'Main') and 'array' (local to function
> 'firstDouble'). Since function 'firstDouble' has a reference to the
> memory location of the object, it has full access to it and can modify
> it.
>
>
> Just prior to function 'firstDouble' exiting, a 2nd array object is
> created on the heap and the reference to that object is assigned to
> variable 'array'. Now we have two independent array objects and three
> references. References 'firstArray' and 'firstArrayCopy' still point to
> the first array object and reference 'array' points to the second.
>
>
> As soon as function 'firstDouble' exits, the reference to the 2nd array
> object is on the stack. However, since it was passed in 'ByVal', it is
> discarded with no further use. Now we still have two array objects and
> two references. However, references 'firstArray' and 'firstArrayCopy'
> still point to the same array object and the 2nd object (created in
> function 'firstDouble') is no longer being referenced and may be
> reclaimed by the Garbage Collection process as appropriate.
>
>
> For the sake of discussion, let's ignore the first array object on the
> heap and pretend there aren't any at this point.
>
>
> When you reach *this* point in your code:
>
> secondArray = New Integer() {1, 2, 3}
> secondArrayCopy = secondArray
>
>
> a new array object is created on the heap, again with two references:
> 'secondArray' and 'secondArrayCopy'.
>
>
> Once again, when function 'secondDouble' is initially called, a copy of
> reference 'secondArray' is passed to the function on the stack creating
> 3 references to that single object: 'secondArray', 'secondArrayCopy'
> and 'array'.
>
>
> Just prior to function 'secondDouble' exiting, another array object is
> created on the heap and the reference to that object is assigned to
> variable 'array'. As soon as function 'secondDouble' exits, the
> reference to the 2nd array object is on the stack.
>
>
> *THIS* time, however, the reference was passed in 'ByRef' and so the
> reference to the new array object is copied from the stack and causes
> variable 'secondArray' to point to that object instead of the first
> object. That is why when function 'secondDouble' exits, 'secondArray'
> and 'secondArrayCopy' are no longer equal - they're pointing to two
> different objects!
>
>
> Ralf
>
>
>
>
>
>
> : *********************************
> :
> : Module modArrayReferenceTest
> :
> : Sub Main()
> : Dim i As Integer
> :
> : ' declare array references
> : Dim firstArray As Integer()
> : Dim firstArrayCopy As Integer()
> :
> : ' allocate firstArray and copy its reference
> : firstArray = New Integer() {1, 2, 3}
> : firstArrayCopy = firstArray
> :
> : Console.WriteLine("Test passing array reference " & _
> : "using ByVal.")
> : Console.Write("Contents of firstArray before " & _
> : "calling FirstDouble: ")
> :
> : ' print contents of firstArray
> : For i = 0 To firstArray.GetUpperBound(0)
> : Console.Write(firstArray(i) & " ")
> : Next
> :
> : ' pass firstArray using ByVal
> : FirstDouble(firstArray)
> :
> : Console.Write(vbCrLf & "Contents of firstArray after " & _
> : "calling FirstDouble: ")
> :
> : ' print contents of firstArray
> : For i = 0 To firstArray.GetUpperBound(0)
> : Console.Write(firstArray(i) & " ")
> : Next
> :
> : ' test whether reference was changed by FirstDouble
> : If firstArray Is firstArrayCopy Then
> : Console.WriteLine(vbCrLf & "The references are " & _
> : "equal.")
> : Else
> : Console.WriteLine(vbCrLf & "The references are " & _
> : "not equal.")
> : End If
> :
> : ' declare array references
> : Dim secondArray As Integer()
> : Dim secondArrayCopy As Integer()
> :
> : ' allocate secondArray and copy its reference
> : secondArray = New Integer() {1, 2, 3}
> : secondArrayCopy = secondArray
> :
> : Console.WriteLine(vbCrLf & "Test passing array " & _
> : "reference using ByRef.")
> : Console.Write("Contents of secondArray before " & _
> : "calling SecondDouble: ")
> :
> : ' print contents of secondArray before procedure call
> : For i = 0 To secondArray.GetUpperBound(0)
> : Console.Write(secondArray(i) & " ")
> : Next
> :
> : ' pass secondArray using ByRef
> : SecondDouble(secondArray)
> :
> : Console.Write(vbCrLf & "Contents of secondArray " & _
> : "after calling SecondDouble: ")
> :
> : ' print contents of secondArray after procedure call
> : For i = 0 To secondArray.GetUpperBound(0)
> : Console.Write(secondArray(i) & " ")
> : Next
> :
> : ' test whether the reference was changed by SecondDouble
> : If secondArray Is secondArrayCopy Then
> : Console.WriteLine(vbCrLf & "The references are " & _
> : "equal.")
> : Else
> : Console.WriteLine(vbCrLf & "The references are " & _
> : "not equal.")
> : End If
> :
> : End Sub ' Main
> :
> : ' procedure modifies elements of array and assigns
> : ' new reference (note ByVal)
> : Sub FirstDouble(ByVal array As Integer())
> : Dim i As Integer
> :
> : ' double each element value
> : For i = 0 To array.GetUpperBound(0)
> : array(i) *= 2
> : Next
> :
> : ' create new reference and assign it to array
> : array = New Integer() {11, 12, 13}
> : End Sub ' FirstDouble
> :
> : ' procedure modifies elements of array and assigns
> : ' new reference (note ByRef)
> : Sub SecondDouble(ByRef array As Integer())
> : Dim i As Integer
> :
> : ' double contents of array
> : For i = 0 To array.GetUpperBound(0)
> : array(i) *= 2
> : Next
> :
> : ' create new reference and assign it to array
> : array = New Integer() {11, 12, 13}
> : End Sub ' SecondDouble
> :
> : End Module ' modPassArray
> :
> : *****************************************
>
>
>
.
- Follow-Ups:
- Re: VB-101: Passing Arrays ByVal vs ByRef
- From: _AnonCoward
- Re: VB-101: Passing Arrays ByVal vs ByRef
- References:
- VB-101: Passing Arrays ByVal vs ByRef
- From: John Pass
- Re: VB-101: Passing Arrays ByVal vs ByRef
- From: _AnonCoward
- VB-101: Passing Arrays ByVal vs ByRef
- Prev by Date: Access Com+ Component on Remote Server
- Next by Date: Re: VB-101: Passing Arrays ByVal vs ByRef
- Previous by thread: Re: VB-101: Passing Arrays ByVal vs ByRef
- Next by thread: Re: VB-101: Passing Arrays ByVal vs ByRef
- Index(es):
Relevant Pages
|