Link to home
Start Free TrialLog in
Avatar of lep1
lep1

asked on

Redim of array not always working

I am sending a double-precision array, x(), to the subroutine listed below, and dimensioning ndx() based on the length of x(), which I obtain from x.GetLength(0) - 1.

However, occasionally the loop hangs because ndx() is a shorter length based on use in a previous subroutine.   Therefore, it seems that the Redim ndx(n) statement does not always force the redimensioning to occur.  

When a
  Public Sub processx(ByVal x)
        Dim i As Integer
        Dim n As Integer = x.GetLength(0) - 1

        Array.Clear(arr, 0, UBound(arr))
        Array.Clear(ndx, 0, UBound(ndx))
        ReDim arr(n)
        ReDim ndx(n)
        For i = 1 To n
            arr(i) = x(i)
            ndx(i) = i
        Next

  End Sub

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger)
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of lep1
lep1

ASKER

arr() and ndx() are sent to an indexed sort routine, where the resulting arr() has sorted x() values (ascending order) and ndx() has the rank of the original values in arr().  Thus, if the original x() was:

x(1)=20
x(2)=5
x(3)=10

returned:

arr(1)=5
arr(2)=10
arr(2)=20

ndx(1)=2
ndx(2)=3
ndx(3)=1
Avatar of lep1

ASKER

Something I didn't mention was that ndx() is used in a threaded subroutine, and I don't know if use of Redim ndx() in a different non-threaded routine (possibly at the same time) will result in a conflict?

Therefore, if you have

Public array() as Double

in a global declaration module, and then use Redim array(10) in a threaded routine the same time you use Redim array(500) in another non-threaded routine, will there be a conflict over using array() in different routines at the same time?  I think this may be happening.
Yes, you would have a conflict. Variable declared in a module are available everywhere, so changing it in the thread also changes it in the non-threaded routine, that does not expects that change.

That is one of the problems of Public variables in a module. They can simplify a few things, but when you have a problem with them, it can come from anywhere. The problem is made worse when you have a multi-threaded application.

I always tell my students that a global variable is a very rare thing. personally, except for debugging, I might have used only one or two since I started using .NET a dozen of years ago.

There is almost always a way to work with variables that have a more limited scope. This is a better use of resources and help preventing unwanted changes. Almost every time I meet a global variable in somebody else code, it is because the programmer lack of knowledge about things you can do in .NET that were not possible to do in a previous environment.

Old VB6 programmers often design their applications as they did before, and they should not. They use global variables because this is what they did before .NET. They do not know how to pass information between two Windows Forms or are used to a permanent connection to a database and have not learned about the connection pooling that works in the background in ADO.NET.

If you Redim your array in 2 different places at the same time, then it's not the same set of data and should not be the same array. You should prepare your thread so that it uses a copy of the array. Arrays have a CopyTo method that does that.
Avatar of lep1

ASKER

Got it, so it sounds like a programmer is setting up their code for an impending disaster if you use Public, and then access those memory registers multiple time with different data in the elements and different lengths(?)

You mentioned the CopyTo command, is that a relatively easy way to overcome this issue.

Last, if I have a count variable like

Public Cnt As Integer

and then use Cnt all over the code in instantiated objects (classes) at the same time in loops for example like

Cnt = 0
For i = 1 To n
  If logical = True Then
      Cnt+=1
  EndIf
Next

Something = Cnt


that Cnt could potentially get mangled?
Well, usually, unless you use threads, you cannot be doing 2 things at the same time. So in your loop, Cnt will do what it is intended to do. But maybe, somewhere else, Cnt has a value of 10. It won't have that value anymore after our loop. When you will get back to that somewhere else later, it is expecting 10 but will find something else : bug.

Since you are giving the value of Cnt to Something in your example, why don't you use Something in the loop. I know it's only an example, but you can see there right there, there is a way to work without using a global variable. There is almost always a way.

Public variables in a module (things are different in a class - and think that a Form is a class) are seen everywhere in the application. It very easy to make a change in one place that will have a negative impact somewhere else.

Public variables hold space in memory even when they are not in use.

If you have a bug with a Public variable, it can come anywhere in your 5 modules, 25 forms and 15 classes. Days of fun if you like debugging.

A local variable takes up memory only while it is in use. As far as you are concerned, it is destroyed when you get out of the method. If you have a bug with it, it,s a lot easier to solve, because the variable is used is a lot smaller scope.

Local variables and block variables (a variable declared Inside of a If...End If, a For...Next or any type of code structure that has a beginning and an end is scoped only to that block, a new thing in .NET for VB6 programmers) are always to be privileged.

If you need a local variable in another method, try as much as possible to pass it as a parameter.

This is not always possible however, specially in Forms, where you might need to see a value in 2 events. Since you cannot pass parameters to events, then you need a variable at the Form (class) level.

If you need to use the same variable in 2 forms, create a constructor, a field or a property in the second form, so that the first one can pass the value as a parameter to the second one.

Global variables (Public variables in a module) are to be banned as much as possible.

Unfortunately, a lot of programmers still use them all the time. Sometimes its for a lack of knowledge, because they have learned programming in older languages that have nothing but global variables (the first version of BASIC for instance). Sometimes, its purely because they are lazy. Its easier to do it than to sit and think. They do not like to code but love debugging :-).

Although I do not have the whole picture, the CopyTo seems indeed to be an easy way out of your problem.
Dim ndx1() As Integer

ReDim ndx1(ndx.GetUpperBound(0))	'So that it is the right size to receive the copy
ndx.CopyTo(ndx1, 0)

Open in new window

Use ndx1 in your thread. Since it is a copy, it is completely independant from ndx and changes that you make on one won't break the job that you are doing on the other.