11.4 For-Next statement

There are three versions of the For statement: A long version, a short version, and a generic version. The generic version of the For statement is also available in long and short versions so that there are actually four different versions of the For statement. For reasons of clarity, however, we stick with just the three different versions in this documentation.

1) Long version For statement:

 
For [Local] <var> = <expr1> To <expr2> [Step <expr3>] <loop-block> Next

The first thing the For statement does, is to set the variable specified by var to the expression specified by expr1. Now the value of the Step statement passed in expr3 defines how to continue. This value is optional. If you do not specify the Step statement, expr3 defaults to the value 1.

If expr3 is positive, the For statement will check if the value of the variable var is less or equal to expr2. If this is the case, the loop will be entered and repeated until the value of var is greater than expr2. At the end of each loop, expr3 is added to the value of the variable <var>

If expr3 is negative, the For statement will check if the value of the variable var is greater or equal to expr2. If this is the case, the loop will be entered and repeated until the value of var is less than expr2. At the end of each loop, expr3 is added to the value of the variable var.

In case expr3 is zero, the loop will be repeated forever. Please do also note that the expressions specified in expr2 and expr3 are only evaluated once, namely at the start of the loop. Thus, the loop limit and step are constant while the loop is active and cannot be modified.

An example:

 
For i = 1 To 100
    DebugPrint(i)
Next

This code prints the numbers from 1 to 100. DebugPrint() is executed a hundred times. When the loop exits, the variable i has the value 101. You see that we did not specify a Step statement. This means that 1 is added each time the loop is repeated. If we would like to progress with factor 2, we could use the following code:

 
For i = 1 To 100 Step 2
    DebugPrint(i)
Next

This will print "1 3 5 7 9 ... 95 97 99". The variable i will have a value of 101 when the loop exits.

If we wanted to count down from 100 to 0, we would have to use a negative step value just as in the following example:

 
For i = 100 To 0 Step -1
    DebugPrint(i)
Next

This calls DebugPrint() a hundred and one times. After the loop exits, the variable i has the value -1.

If you add the Local identifier before the variable initialization, the For statement will create the iterator variable locally to the loop block. This means, that it cannot be accessed from outside the loop block. An example:

 
For Local i = 1 To 50
    DebugPrint(i)      ; prints 1, 2, 3 ... 49, 50
Next
DebugPrint(i)          ; prints 0 (i is only available inside the loop)

The advantage of For loops that use a local iterator variable is that they run faster than loops that use a global variable. If you do not need to access the variable of the For statement from outside the loop, you should always use the Local identifier. A limitation of For loops with the Local identifier is that you must not assign a new value to the local iterator value. If you need to exit the loop, use Break. Modifying the iterator variable during the loop's execution works only without the Local identifier.

You may also want to have a look at the documentation of the Break and Continue statements. These can be used to exit from a loop or to jump to the end of it.

2) Short version For statement:

 
For [Local] <var> = <expr1> To <expr2> [Step <expr3>] Do <stat>

The short version behaves exactly like the long version but you do not have to include the Next statement. The short For statement has the restriction that the loop block must only consist of one statement. If you need to execute multiple statements in the loop block, you have to use the long version. The identifier Do signals Hollywood that you want to use the short version.

The first example from above could be written in the following way using the short For statement:

 
For i = 1 To 100 Do DebugPrint(i)

3) Generic version For statement:

 
For <var1> [, <var2>, ...] In <expr> [Do <stat>] or [<loop-block> Next]

The generic version of the For statement is different from the other two versions through the fact that it calls a user-defined function to retrieve the values for each iteration. This fact makes the generic For statement suitable for a wide variety of purposes. You can write your own iterator functions but for most cases you will likely use the inbuilt iterator functions that are provided by functions such as Pairs(), IPairs(), or PatternFindStr().

The expression specified in expr is evaluated only once. It has to return three values: An iterator function, a state value, and an initial value for var1. The iterator function and the state value are private values and they are neither visible nor accessible as variables during the For loop's runtime. Once the generic For loop has retrieved these three values, it will start calling the iterator function with the state value and current value of var1 as the two arguments. The loop will be terminated as soon as var1 becomes Nil.

Most iterator functions return multiple values for each iteration. That is why you can also specify multiple variables in the generic For statement. The ability to have multiple variables initialized to different iteration states makes the generic For statement very flexible.

Let's have a look at an example now. Consider the following table:

 
months = {"January", "February", "March", "April", "May", "June",
     "July", "August", "September", "October", "November", "December"}

We now want to be able to find out the index of a month (1 to 12) by using its name as a reference. Of course, we could iterate over the table, compare the name of the month to the one we are looking for, and thus find out the appropriate index. But when dealing with larger amounts of data, it is often faster to create a reverse table to find out the desired information. In our case, we want a table that uses the name of the months as indices so that table["January"] returns 1, table["February"] returns 2, and so on. We can easily create this reverse table using the generic For loop together with the iterator function provided by IPairs(). The IPairs() function will return an iterator function that returns two values: the index value as well as the key value for each table element that is passed to it. We can use this iterator function to reverse the table very easily:

 
revmonths = {}
For i,v In IPairs(months)
   revmonths[v] = i + 1
Next

Alternatively, we could also use the short version of the generic For statement for this code because there is only one statement in the For loop. Using the short version of the generic For statement the code would look like this:

 
revmonths = {}
For i,v In IPairs(months) Do revmonths[v] = i + 1

The IPairs() function will only iterate over all integer indices in a table. If you want to traverse all fields of a table, you can use the Pairs() function instead.

Another command that is often used in conjunction with the generic For statement is the PatternFindStr() function. It will return an iterator function that can be used to parse a string. For example, the following code will iterate over all words in a string:

 
s$ = "Hello World This is a test"
For w$ In PatternFindStr(s, "%a+") Do Print(w$)

Of course, it is also possible to write own iterator functions. This, however, can get quite complicated. That is why it is not explained here. Please consult the book "Programming in Lua (second edition)" by Roberto Ierusalimschy for more information on how to write own iterator functions.


Show TOC