Lua's Numeric For Loop


As we learned in the previous sections, the while and repeat control structures allow a program to loop over a block of code until a specified condition is met. These are sometimes called "condition-controlled" loops.

Another common loop is called a "count-controlled" loop, in which the loop iterates a specified number of times. In Lua, this type of loop is called the "Numeric For Loop".

The general pattern for the numeric for loop is:

for [var] = [start], [stop], [step=1] do
    -- loop body
    -- repeat for each specified iteration
end

where var is an arbitrary variable name that is locally-scoped to the loop body, and the start, stop, and (optional) step parameters define "how" the loop will execute.

Loop execution can be more easily understood by considering it to proceed in two parts, which we could call initialization and iteration.

Initialization

When the Lua encounters a for loop, the first thing it does is evaluate each of the start, stop, and (optional) step expressions, which are used to generate a sequence of numbers that will define:

  1. How many times the loop body will execute, and

  2. What values will be assigned to var prior to each iteration of the loop.

Each number in the generated sequence will be assigned to var, one by one, until the sequence is exhausted. The first number in the loop is the value assigned to start, then the second number is start + step, then the third in start + 2 * step, and so on:

var = start
var = start + 1 * step  -- first iteration
var = start + 2 * step  -- second iteration
var = start + 3 * step  -- third iteration
...
var = start + n * step  -- nth iteration

This list continues for n steps, until start + n * step >= stop. When step is not specified, it is assigned a default value of 1.

Iteration

Now that we have initialized the loop, we can move to the iteration step. In this step, the loop body is execute once for each value of var in the "iteration list". The main point of this step is to define the loop body so that it performs the correct operations given each value of var.

Examples

Let's take a look at a few examples:

Example 1

In the first example, let's consider a simple loop that counts from 0 to 5:

for x = 0, 5 do
    print("x = " .. x)
end

When executed, this loop generates the following output:

x = 0

x = 1

x = 2

x = 3

x = 4

x = 5

Example 2

As a second example, let's pick another simple with a step value of 2:

for x = 0, 10, 2 do
    print("x = " .. x)
end

This loop behaves similarly to the previous example, except for the value assigned the x.

x = 0

x = 2

x = 4

x = 6

x = 8

x = 10

Example 3

Finally, as a final example, let's look at a slightly more complicated case that requires the stop and step parameters to be evaluated prior to generating the sequence of values to iterate over:

for x = 0, 2 * 3.14, 3.14 / 2 do
    print("x = " .. x)
end

Although the mechanics of generating the loop values is slightly different, loop operation remains basically the same:

x = 0.0

x = 1.57

x = 3.14

x = 4.71

x = 6.28

Early Termination

Although the basic operation of the numeric for loop is to repeat the loop body for a pre-determined number of iteration, it is possible to terminate the loop early if needed. This is generally done using break, although a loop inside of a function can also terminate early when a return is encountered:

break

In order to demonstrate break we will use the following shamefully-contrived example. In this example, the loop parameters call for iterating the loop 6 times, but the loop body contains code to terminate the loop early if a specific condition is encountered:

for x = 0, 5 do
    if x == 3 then
        break
    end

    print("x = " .. x)
end

When this loop executes, it generates the following output:

x = 0

x = 1

x = 2

This is obviously a contrived example, but shows a pattern that can be helpful in cases where the loop parameters define the maximum number of times that the loop will iterate, while containing additional logic enforcing condition under which the loop should terminate early.

return

As with the "condition-controlled" loops we look at previously, the return statement can also be used terminate a "numeric for" loop early when operating inside a function. The following code demonstrates this with a similar implementation:

local function count()
    for x = 0, 5 do
        if x == 3 then
            return
        end

        print("x = " .. x)
    end
end

count()

which produces the following output:

x = 0

x = 1

x = 2