Question Mysterious problem: Program does NOT do what it is being told

Alex167

New member
Joined
Aug 24, 2011
Messages
4
Programming Experience
1-3
Please take a look at the following code, which is a simplified extract from my actual code:

-----

Public Sub Main()

Dim arrWhatever(9) As Whatever
Dim arrTemp(4) As String

For i As Integer = 0 To 9

arrWhatever(i) = New Whatever

'ReDim arrTemp(4) '-> When activated, correct inputs are passed. When deactivated, new inputs overwrite all previously passed inputs.
For j As Integer = 0 To 4
arrTemp(j) = "File" & 5 * i + j
Next j

arrWhatever(i).Inputs = arrTemp '-> When ReDim statement is NOT activated, for e.g. i=3, arrTemp is not only passed to arrWhatever(3).Inputs but also to arrWhatever(0).Inputs, arrWhatever(1).Inputs and arrWhatever(2).Inputs (i.e. all previous Whatever classes), which is not supposed to happen !!!

Next i

Debug.Print(arrWhatever(0).Inputs(0))
Debug.Print(arrWhatever(1).Inputs(0))
Debug.Print(arrWhatever(2).Inputs(0))

Debug.Print(arrWhatever(0).Inputs(1))
Debug.Print(arrWhatever(1).Inputs(1))
Debug.Print(arrWhatever(2).Inputs(1))

End Sub

Public Class Whatever

Public Inputs() As String
Public Outputs() As String

Public Sub GenerateOutputs()
'Generates Outputs from Inputs
End Sub

End Class

-----

I am generating an array of 10 Whatever classes and want to pass different strings to the public array Inputs() of each Whatever class.

I am creating a temporary array arrTemp with the strings I need and then pass this array to the public array Inputs() of each Whatever class.


1.) When I do NOT use the ReDim statement to delete all elements of my temporary array arrTemp, the following happens:

First loop (i=0):

The code fills arrTemp with the following strings: { "File0", "File1", "File2", "File3", "File4"}
Then the strings are passed to arrWhatever(0).Inputs

Second loop (i=1):

The code overwrites the previous values of arrTemp and fills it with the following strings: { "File5", "File6", "File7", "File8", "File9"}
Then the strings are passed to arrWhatever(1).Inputs

When this is being done, arrWhatever(0).Inputs is also filled with these news strings, overwriting its previous values, although the instruction for the program is clearly to pass the new strings only to arrWhatever(1).Inputs

For the whole program, debug output is as follows:

File45
File45
File45
File46
File46
File46


2.) When I DO use the ReDim statement to delete all elements of my temporary array arrTemp before filling it with new values, everything works perfectly.

For the whole program, debug output is as follows:

File0
File5
File10
File1
File6
File11


Question: Why do I need to use the ReDim statement for my program to work correctly?


Please do NOT question the architecture of my program. It's just a simplified version and there is a reason why the architecture is like it is.

All I would like to understand is why my program works perfectly with the ReDim statement but overwrites all previously passed inputs when I do NOT use the ReDim statement.


Any help would be higly appreciated. I find it scary NOT to understand the logic behind this phenomenon.


Thanks,

Alex
 
Arrays are reference types, and you only declare one array object outside the loop and use that in all loop iterations.
ReDim statement creates and assigns a new array to the variable. It is described under 'behaviour' in this help page: ReDim Statement (Visual Basic)
Why do I need to use the ReDim statement for my program to work correctly?
You don't actually, you can also create new arrays each loop. Keeping the narrowest scope when declaring variables is a good idea for many reasons.
 
''Didn't see your post JohnH, was writing it. I'll leave this here anyways


Question: Why do I need to use the ReDim statement for my program to work correctly?

All I would like to understand is why my program works perfectly with the ReDim statement but overwrites all previously passed inputs when I do NOT use the ReDim statement.


When you don't use the redim you are passing a reference to the variable "arrTemp" into all of the objects in "arrWhatever". Since this is a temporary variable it would probably make more sense to create a instance of it in the for loop like this: (or you can just use the redim statement like you showed in your code, which reinitialize the array)

        Dim arrWhatever(9) As Whatever
        'Dim arrTemp(4) As String 'moved

        For i As Integer = 0 To 9
            Dim arrTemp(4) As String 'to here ' creates a new string() for each

            arrWhatever(i) = New Whatever

            For j As Integer = 0 To 4
                arrTemp(j) = "File" & 5 * i + j
            Next j

            arrWhatever(i).Inputs = arrTemp
        Next i
 
Last edited:
Thanks for your answers.

I have been working with arrays for quite some time but I never viewed them as reference types. Apparently, it never made a difference :)


Just to make sure I understood this correctly:

The statement arrWhatever(0).Inputs = arrTemp basically links all elements in Inputs to the corresponding elements in arrTemp, i.e. Inputs(0) to arrTemp(0), Inputs(1) to arrTemp(1), etc

So if an element in arrTemp is changed, the corresponding element in Inputs changes as well.

But at the very moment when arrtemp is re-initialized (ReDim statement) or becomes invalid (declaration within loop), the reference changes to its latest value (i.e. Inputs does not any more contain a reference but from now on a value).

Is that correct?


But if arrTemp was NOT an array of string but only a normal string variable, then it obviously would NOT be a reference but a value?

Correct?


Thanks,
Alex
 
Last edited:
Think it this way. Let's say that I live in a house. The walls of my living room are blue. Now, let's say that you move in to share the house.
VB.NET:
You.House = Me.House
How many houses are there? Just one, right? What colour are the walls of your living room? Blue, right? Now, if you paint the walls of your living room yellow, what colour are the walls of my living room? Would you say that you changed the colour of the walls in your living room so the colour of the walls in the corresponding room in my house were changed? There are no corresponding rooms because there's only one house.

The same goes in that code. There's only one array. Changing an element in that array changes an element in that array, period. You might access that array via arrTemp, arrWhatever(0).Inputs or some other variable. It doesn't matter. It's still the same array.

By the way, String is a class too, so String variables contain a reference, not a value, just like all classes. The difference with Strings is that they are immutable, i.e. they cannot be changed once created. To "change" a String object you must actually create a new String object that contains the changes, while the original object is unchanged.
 
According to your logic: If I destroy all rooms in the house, there are no more rooms, right?

But if I destroy all values in arrTemp (for example, using the ReDim statement), arrWhatever(i).Inputs is NOT being destroyed but still contains the values that arrTemp initially had.

Doesn't that undermine the logic that there is only one array and consequently the "one house analogy"?
 
Redim statement creates a new 'house'. The old house remains as long as someone can remember where to find it.
 
According to your logic: If I destroy all rooms in the house, there are no more rooms, right?

But if I destroy all values in arrTemp (for example, using the ReDim statement), arrWhatever(i).Inputs is NOT being destroyed but still contains the values that arrTemp initially had.

Doesn't that undermine the logic that there is only one array and consequently the "one house analogy"?
Analogies can only go so far but what you suggest is not what actually happens. Using ReDim does not destroy anything. Arrays are fixed-size, i.e. once you create one you cannot change its size. What ReDim does is actually create a new array with the new size and assign it to the variable. The old array still exists and, consequently, any other variables that referred to it still refer to it. This code:
Dim numbers(10) As Integer

ReDim numbers(20)
is functionally equivalent to this:
Dim numbers() As Integer = New Integer(10) {}

numbers() = New Integer(20) {}
 
Back
Top