for i = 0 to 10... count on i after for has exited?

Can we count on the current behavior of the for loop? For example:

dim i as Integer
for i = 0 to 10
  if i = 5 then
    exit for i
  end if
next

Print Str(i) // prints 5

Also, when not exiting early:

dim i as Integer
for i = 0 to 10
  // do something
next

Print Str(i) // prints 11, i.e. ran until i incremented > 10

It is not documented as to what i should be in these cases, but the docs at least rely on this to be the case in one example. Can we trust this will always be the case in our code also?

that is how it is in every language I have used since the early 80’s
but that being said… I would not rely on the 2nd example always being true in the future.

I do. i is tested against the loop constraints and the looping ends when i has been incremented to the first value above 10 which is 11. There is no other possibility.

The 2nd case is actually used in the documentation. It is a very convenient way of determining if a loop as exited prematurely due to some condition in the loop.

Although I don’t recall which, I’ve used languages where i = upper bound after exit.

If I recall correctly, For next has been behaving like this since the first days of interpreted basic.

It should be fairly stable.

AppleScript leaves the index variable set to the upper bound on normal exit, for example.

What say you, @Joe Ranieri ?

I didn’t say it wasn’t true now in Xojo

It’s bad programming anyway, to use a counter after the loop. Don’t do it. That was one of my early bad practices - I know it’s tempting - but don’t do it. Use a variable for one purpose, not multiple purposes. In this case you are using it for a counter and for an actual value. I KNOW you are using the loop to increment the counter as to use the value, but in reality you can still separate the purposes. Let the counter count. Deal with your value on it’s own.

Be a good programmer FIRST.

[code]
Dim ThisVal As Integer
Dim i As Integer
ThisVal = -1
For i = 0 To 10
// code that tests something, if test true, apply value to ThisVal then exit
Next

if ThisVal > -1 Then
// operate on ThisVal
else
// raise an error or do something else
end if[/code]

I do not see where that is a poor programming practice at all. We often use loops to increment a value, then bounce of the loop when a particular condition is met. The value of the counter can be important in that case, depending upon what you are doing in the loop and what exactly you are doing with the value when processing in the loop is completed.

Where would you get the idea that was poor programming practice?

I admit, it would not be a good idea in say, Smalltalk, but Xojo is not a very much like small talk. Xoxo seems to encourage object oriented designs much more than object oriented programming.

The actual programming language seems very procedural, with loops and evaluations. It actually seems to be a very good implementation of Object Oriented Design -> Object/Procedural programming hybrid environment. sing the incremented value of a counter variable - especially one with a definition outside the loop statement - appears to me to be quite acceptable.

You should move the loop variable into the loop. Then it is not accessible after the Next statement.

[code]Dim ThisVal As Integer = -1

For i As Integer = 0 To 10
// code that tests something, if test true, apply value to ThisVal then exit
Next

If ThisVal > -1 Then
// operate on ThisVal
Else
// raise an error or do something else
End[/code]

I strongly disagree that using the loop counter is bad practice, especially in nested loops where you are looping through the same array of data. Creating multiple variables to accomplish the same task could be considered a bad practice as well. Now, I will say that the need to do this and the places that it will make your code more clear do not occur on a daily basis, but when it does, it should be used. The less code that exists, the less opportunity for bugs especially if you begin creating multiple variables for the same purpose, which one should you use? You’ll get that wrong sooner or later.

I usually do

For i as integer = 0 to 10 //do stuff Next

As a result, I am not tempted to use the residual value of i.

The end value is available inside the loop, so I could do :

dim theValue as integer For i as integer = 0 to 10 //do stuff theValue = i if something then exit end if Next

theValue will be 10 after the loop, unless exit.

The trick of using i = 11 to know if the loop completed is probably not a major sin, but it is kind of illogical. For 1 to 10 IMHO should never mean anything but the maximum, here 10.

To me, not taking advantage of the loop variable is not taking advantage of functionality the language gives to you to make your programs more concise w/o loosing readability.

Whatever works for you. However, how many times do you need to ascertain the loop completed versus exited ? In my several decades experience, almost never. So as I said, using the technique described in the LR should not be taboo. It is just not very logical.

and then you have to sometimes deal with “DOWNTO”, “STEP” all of which affect the exit value
and some languages have no “break” or “continue” and this forces you to set index to max+1
So I stand behind my opinion of “never use a loop index value outside of the loop it indexes”

Actually, I found the example in the LR after my code was written, and I do not use it in that manner. That being said, if you know that you can do it and trust your knowledge of the language, it may have opened opportunities in the past to have made code more concise, which in my book as long it does not harm code readability then it is a good thing. Concise code for being concise and doing so to the point of hurting readability is a terrible no no of course.

However, not everyone should trust me, recently in my decades of experience, I have found a use for Goto… something that is sure to raise quite a few discussions :slight_smile:

To me, if the language gives you a feature, you should use that feature to make your code easier to understand and more concise. Is it something to use on a continual basis? Nope, already said that, but when it fits and solves a problem more simply than other methods, use it and enjoy your knowledge of the language.

lets be careful with those “four letter words” :smiley:

and remember, sometimes a “feature” is a “design oversight”, or “the easy way to implement”, or worse “it was always done that way”

and I “defy” (yeah strong word), you to come up with ANY situation that cannot be coded in an OOP Language like XOJO without the need to use “GOTO” … it had its place in procedural languages like MSBasic, AppleSoft and the like

Here is something I just whipped up as an example.

  dim people() as Person
  
  // Load a bunch of people from a database or something by age
  
  dim currentAge as Integer
  dim personIndex as Integer
  dim peopleUbound as Integer = people.Ubound
  
  while personIndex <= peopleUbound
    currentAge = people(personIndex).Age
    Print "People Aged " + Str(currentAge)
    
    for personIndex = personIndex to peopleUbound
      dim p as Person = people(personIndex)
      if p.Age <> currentAge then
        exit for personIndex
      end if
      
      Print " * " + people(personIndex).Name
    next
    
    Print ""
  wend

So, rewriting it without relying on personIndex after the for loop exits, you could of course do this:

  dim people() as Person
  
  // Load a bunch of people from a database or something by age
  
  dim currentAge as Integer
  dim personIndex as Integer
  dim peopleUbound as Integer = people.Ubound
  
  while personIndex <= peopleUbound
    currentAge = people(personIndex).Age
    Print "People Aged " + Str(currentAge)
    
    for i as Integer = personIndex to peopleUbound
      dim p as Person = people(i)
      if p.Age <> currentAge then
        personIndex = i
        exit for i
      end if
      
      Print " * " + people(i).Name
    next
    
    Print ""
  wend

I just don’t see the reason. Notice how you have to then decide between i, or personIndex and also how you still have to update personIndex to be i, which is the same as just accessing i itself…

BTW… all the code was just typed in, not tried in real life. My code is quite a bit different, but exhibits the same idea.

You are really sharing a loop variable between two interwoven loops?