FOR...NEXT loop index becomes 1 instead 0

I don’t know whether the following is a bug or a feature. I have XOJO 2022R1.

I have actual an ARRAY with one element. The index of the element must be known later in the logic.

var i as integer
for i = 0 to MyArray.LastIndex
  <...some logic...>
next

After the LOOP is index I = 1. I expected I = 0.

But if I write

var i as integer
for i = 0 to MyArray.LastIndex
  <...some logic...>
  if i = MyArray.LastIndex then
    exit
  end if
next

After the LOOP is index I = 0. That is what I expected.

If the array doesn’t have any entries then LastIndex = -1. After adding an entry then LastIndex = 0.

Why the torturous code?

dim i as integer = MyArray.Lastindex

No for’s needed.

The array grows during processing. Each element contains another array besides some fields. I have to search the fitting entry.

This is documented here. Upon hitting the Next statement, the counter is incremented. That’s how the loop structure knows to end/continue. It could be done differently, but it’s not.

If your array is changing during the loop, why can’t you just add the following after the loop to get the correct end value:

i = MyArray.LastIndex

Or, perhaps:

i = i - 1

From the docs:

Var i As Integer
For i = 1 To 10
  ...
Next
// i is now 11

Imagine a For…Next as this While…Wend:

var max as Integer = 10
var index as Integer = 1
while index <= max
  ...
  index = index + 1
wend

Okay i see the index becomes one bigger than the count of elements is.

I have this problem only if nothing fitting was found into the loop. If a matching entry is found, the loop is exited with exit and the index is correct

I probably wouldn’t change the original array during the loop to begin with, but make a copy (build a new array) with the elements I need as the result.

Yes, that is possible. I always try not to count up my own index. I wanted to use the variable from the loop.
I was just not sure if the index variable of XOJO after the LOOP contains the correct value like this.

Yikes.
If so, I wouldnt trust

for i = 0 to MyArray.LastIndex

So MyArray.LastIndex might be 12 on entry, and 14 after the loop?

If you want to know if something exists, for clarity I’d use a separate variable, and do the insert afterwards, (ie not during the loop) if no match was found


var nFoundPos as integer = -1
var nStartMax as integer = MyArray.LastIndex
for i as integer = 0 to nStartMax
   if {some logic} then  nFoundPos = i
next
if nFoundPos = -1 then
//add a new array element
nFoundPos = MyArray.LastIndex
end if

Since the maximum is not a pre-declared variable with static value, it is re-calculated on each iteration. Which can lead to slow code on massive arrays or exceptions if you’re not careful.

As an example, this code should run until it hits an exception:

var myArray() as Integer = Array( 0 )

var index as Integer
for index = 0 to myArray.LastIndex
  myArray.Add( 1 )
next index

The array grows not into this loop, but in the processing of the data.

But your solution is the right for me.

I already have a declaration like your “nFoundPos”, but didn’t think to set the index correctly there.
Somehow I didn’t realize that the index at the end of the loop is 1 greater than the number of elements in the array.

The growing of the array did not happen into this loop. But thank you for the hint.

But you did say:

If that’s not the case, you should set your maximum to a variable for use in the For statement.

1 Like

Yes. The growing of the array takes place before the loop. Here at this point I am just looking for the correct entry to determine the array contained in the array line.
The content depends on user input. These can change at any time.

So that it does not remain so abstract:

My class Class_mapping is used for a structure mapping. Each mapping line contains an array for a field mapping (class Umschlüsselung). The whole thing depends on the input of the user.

Then something like this would be more appropriate:

var i as integer
var max as Integer = MyArray.LastIndex
for i = 0 to max
  <...some logic...>
next
'// Reference the max variable later as it already
'   contains the index of the last array item
'   or i if you're exiting when a condition is met
'   a simple check:
if i > max then
  ...
end
'// or, if you need a value for some reason...
i = Min(i, max)

I thank you all for the kind help!

My code is now:

var found as boolean
var i as integer
for i = 0 to myArray.LastIndex 'array for structure mapping
  '<...Some logic with an exit if the right element of the array was found. Thereby found = true is set...>
next
if not found then
  i = i - 1
 '<...some logic to create the first entry of the array into myArray(i).FieldMapping ...>
end if

It works!

but for a large array, it should still be faster to replace

for i = 0 to myArray.LastIndex

with

for i = 0 to TheValueofLastIndexBeforeTheLoopStarted

1 Like

And it’s a good habit to get into, also. Faster under some circs and avoids potential errors.

In my 50 years of programming I have never come across a language where the value of a For loop index variable was defined after the loop exited. This is even more problematic if the step size is something other than 1. I always assign a separate variable the requisite index value before exiting the loop and use that.

1 Like

I was on the wrong track. But I didn’t realize that until a moment ago.
The new solution is much simpler, it is inside the loop before it can be left with EXIT. So I don’t need an extra variable anymore.
And the problem with the index doesn’t even arise.