VB-101: Passing Arrays ByVal vs ByRef

G

Guest

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

*********************************

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

*****************************************
 
K

Ken Tucker [MVP]

Hi,

The array is passed byval. Anything you do to the array in the
subroutine will not be sent back. If you want to be able to make any
changes to the array pass it byref.

Ken
--------------------
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

*********************************

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

*****************************************
 
A

_AnonCoward

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

Herfried K. Wagner [MVP]

John Pass said:
' 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.

Arrays are reference types while 'Integer' is not. Consequently an array of
integers is a reference type. By passing the array to the method using
'ByVal' the pointer to the array gets copied and the copy is passed to the
method. Thus you can change the array's elements, but you cannot change the
whole array. In other words, assigning a new array object to the paramater
won't change the reference of the variable being passed to the method.
You'll have to pass the array 'ByRef' in order to be able to do that.
 
G

Guest

Passing an array byval is exactly like passing any other object byval - any
change to the object internals is seen in the calling code. So *every*
change except any change to the actual array object pointer *is* sent back.

David Anton
www.tangiblesoftwaresolutions.com
Home of the Instant C# VB.NET to C# converter
and the Instant VB C# to VB.NET converter
 
G

Guest

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
 
G

Guest

Herfried, Thanks for your explanation as well.

You write: 'assigning a new array object to the paramater
won't change the reference of the variable being passed to the method'.

Do you mean that for the code section of line 99? :
'array = New Integer() {11, 12, 13}'
That would mean that a new object is created rather than the old one's data
are overwritten.

Please also look at my longer response to _AnonCoward.

Thanks for your explanation,

John
 
G

Guest

Ken, Thanks for your response.
My questions was why the 2nd part of the sub did not change the changes the
output to screen while the 1st part did.
Please see my (longer) resonse to _AnonCoward.

Regards,

John.
 
H

Herfried K. Wagner [MVP]

John Pass said:
You write: 'assigning a new array object to the paramater
won't change the reference of the variable being passed to the method'.

Do you mean that for the code section of line 99? :
'array = New Integer() {11, 12, 13}'
That would mean that a new object is created rather than the old one's
data
are overwritten.

Yes. You are creating a new array and assign it to the method's parameter.
If the parameter is passed 'ByVal', the array passed to the method in the
parameter is not changed, because you are assigning the new array to a
temporary copy of the array pointer passed to the method.

\\\
Public Sub Foo1(ByVal Bla() As Integer)
Bla = New Integer() {10, 20}
End Sub

Public Sub Foo2(ByRef Bla() As Integer)
Bla = New Integer() {10, 20}
End Sub
..
..
..
Dim a() As Integer = {1, 2}
Foo1(a)

' 'a' still points to the array containing {1, 2}.

Foo2(a)

' 'a' points to the array containing {10, 20}.
///
 
G

Guest

David, Thanks for your response.
My real questions was why the 2nd part of the sub did not change the changes
the output to screen while the 1st part did.
If every change is sent back, why not the changes made by the 2nd part of
the sub.
Please see my (longer) response to _AnonCoward.

Regards,

John
 
A

_AnonCoward

:
: 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.


No. The variables 'firstArray', 'firstArrayCopy' (in sub Main) and
'array' in function 'firstDouble' *all* point to the *same* instance of
an array object. They are three separate references to the same thing.


Any changes to the underlying object made by using any of those
references will be seen by all references to that object.


For example, try this little experiment:

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Option Strict
Imports Microsoft.Visualbasic
Imports System

Public Class [class]

Public Shared Sub Main()
Dim i As Integer

Dim firstArray As Integer()
Dim firstArrayCopy As Integer()

firstArray = New Integer() {1, 2, 3}
firstArrayCopy = firstArray

'*********************************************
'At this point, firstArray and firstArrayCopy
'are referencing the same array object
'*********************************************

Console.WriteLine("Contents of 'firstArray':")
For i = 0 To firstArray.GetUpperBound(0)
Console.Write(firstArray(i) & " ")
Next
Console.WriteLine()

Console.WriteLine("Contents of 'firstArrayCopy':")
For i = 0 To firstArrayCopy.GetUpperBound(0)
Console.Write(firstArrayCopy(i) & " ")
Next
Console.WriteLine()

Console.WriteLine("Changing 'firstArrayCopy(0)':")
Console.WriteLine()
firstArrayCopy(0) = 4

Console.WriteLine("Value of 'firstArray(0)':")
Console.WriteLine(firstArray(0))

End Sub

End Class

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++


This will generate the following output:

Contents of 'firstArray':
1 2 3

Contents of 'firstArrayCopy':
1 2 3

Changing 'firstArrayCopy(0)':

Value of 'firstArray(0)':
4


Note that the change to element(0) of firstArrayCopy is reflected in
firstArray. This is because both references are pointing the *same*
array object. In your code, when function 'firstDouble' is called,
parameter 'array' is a third reference to that same object in memory.


: 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.


Hopefully this is a little clearer. Parameter 'array' is a reference to
the same array object that 'firstArray' and 'firstArrayCopy' are
pointing to. Since the underlying array object is the same, any changes
made anywhere are seen everywhere.


When you created a new array object (with values 11, 12, 13) and
assigned it to parameter 'array' (in functions 'firstDouble' and
'secondDouble'), you created a brand new array object on the heap. This
object is independent from the original array object. At this point,
parameter 'array' no longer references the same object as 'firstArray'
or 'firstArrayCopy'.


Since parameter 'array' was passed into function 'firstDouble' as
'ByVal', when that functions returns, the new memory location it's
referencing is discarded.


However, when you call function 'secondDouble', the 'ByRef' keyword
instructs the compiler to grab whatever memory location 'array' is
referencing at the point the function exits and assign the value to
variable 'secondArray'. At that point, 'secondArray' and
'secondArrayCopy' no longer reference the same object.


: 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.


Yes.


: 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?


Because parameter 'array' is not an array object itself - it is a
*reference* to an array object (a pointer in C++). The parameter
'points' to the object it is referencing. The statement ('array = New
array() {11, 12, 13}' creates a new array object in memory then assigns
the value that memory location to parameter 'array'.


: 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.


It's one instance of the array class type.


: Thanks for you explanation,
:
: John


You're welcome.


Ralf

<snip>
 
G

Guest

Thanks a lot Ralf, it is now clear!

Regards,

John


_AnonCoward said:
:
: 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.


No. The variables 'firstArray', 'firstArrayCopy' (in sub Main) and
'array' in function 'firstDouble' *all* point to the *same* instance of
an array object. They are three separate references to the same thing.


Any changes to the underlying object made by using any of those
references will be seen by all references to that object.


For example, try this little experiment:

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Option Strict
Imports Microsoft.Visualbasic
Imports System

Public Class [class]

Public Shared Sub Main()
Dim i As Integer

Dim firstArray As Integer()
Dim firstArrayCopy As Integer()

firstArray = New Integer() {1, 2, 3}
firstArrayCopy = firstArray

'*********************************************
'At this point, firstArray and firstArrayCopy
'are referencing the same array object
'*********************************************

Console.WriteLine("Contents of 'firstArray':")
For i = 0 To firstArray.GetUpperBound(0)
Console.Write(firstArray(i) & " ")
Next
Console.WriteLine()

Console.WriteLine("Contents of 'firstArrayCopy':")
For i = 0 To firstArrayCopy.GetUpperBound(0)
Console.Write(firstArrayCopy(i) & " ")
Next
Console.WriteLine()

Console.WriteLine("Changing 'firstArrayCopy(0)':")
Console.WriteLine()
firstArrayCopy(0) = 4

Console.WriteLine("Value of 'firstArray(0)':")
Console.WriteLine(firstArray(0))

End Sub

End Class

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++


This will generate the following output:

Contents of 'firstArray':
1 2 3

Contents of 'firstArrayCopy':
1 2 3

Changing 'firstArrayCopy(0)':

Value of 'firstArray(0)':
4


Note that the change to element(0) of firstArrayCopy is reflected in
firstArray. This is because both references are pointing the *same*
array object. In your code, when function 'firstDouble' is called,
parameter 'array' is a third reference to that same object in memory.


: 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.


Hopefully this is a little clearer. Parameter 'array' is a reference to
the same array object that 'firstArray' and 'firstArrayCopy' are
pointing to. Since the underlying array object is the same, any changes
made anywhere are seen everywhere.


When you created a new array object (with values 11, 12, 13) and
assigned it to parameter 'array' (in functions 'firstDouble' and
'secondDouble'), you created a brand new array object on the heap. This
object is independent from the original array object. At this point,
parameter 'array' no longer references the same object as 'firstArray'
or 'firstArrayCopy'.


Since parameter 'array' was passed into function 'firstDouble' as
'ByVal', when that functions returns, the new memory location it's
referencing is discarded.


However, when you call function 'secondDouble', the 'ByRef' keyword
instructs the compiler to grab whatever memory location 'array' is
referencing at the point the function exits and assign the value to
variable 'secondArray'. At that point, 'secondArray' and
'secondArrayCopy' no longer reference the same object.


: 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.


Yes.


: 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?


Because parameter 'array' is not an array object itself - it is a
*reference* to an array object (a pointer in C++). The parameter
'points' to the object it is referencing. The statement ('array = New
array() {11, 12, 13}' creates a new array object in memory then assigns
the value that memory location to parameter 'array'.


: 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.


It's one instance of the array class type.


: Thanks for you explanation,
:
: John


You're welcome.


Ralf

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top