Re: VB-101: Passing Arrays ByVal vs ByRef





"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
:
: *****************************************


.



Relevant Pages

  • Re: VB-101: Passing Arrays ByVal vs ByRef
    ... if passed ByVal, does not change the original array data in memory, because ... "an array object is created on the heap with two references". ... SecondDoublewould be a reference to firstArray and not a new object. ... > 'secondArray' and 'secondArrayCopy'. ...
    (microsoft.public.dotnet.languages.vb)
  • Re: VB-101: Passing Arrays ByVal vs ByRef
    ... My questions was why the 2nd part of the sub did not change the changes the ... > changes to the array pass it byref. ... > ' new reference ... > ' allocate secondArray and copy its reference ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Need help with textboxes
    ... The JavaScript 1.5 Reference already states: ... All forms and their children are stored in an array ... use dot notation or object literals. ... No. Bracket property accessors allow their argument to be any string value. ...
    (comp.lang.javascript)
  • Re: Garbage Collection Issues in long-standing services
    ... the pinned array should get unpinned or ... The receive case is done quite well, I do create a 4K buffer and reuse it ... and remove the reference to my wrapper socket class, ...
    (microsoft.public.dotnet.languages.csharp)
  • VB-101: Passing Arrays ByVal vs ByRef
    ... if an array is passed by Val. ... ' new reference ... Dim firstArray As Integer ... Dim secondArray As Integer ...
    (microsoft.public.dotnet.languages.vb)