CodeRigor

LESSON

Repeat steps with for and while

Repeat a block a fixed number of times with for or until a condition changes with while, keep running totals, and avoid off-by-one mistakes.

Computers are good at doing the same thing many times without getting bored or making slips. A loop is a statement that runs a block of code repeatedly. Lua has two loops you will use all the time: for, when you know how many times to repeat, and while, when you want to repeat until something changes.

for repeats a fixed number of times

Lua
for i = 1, 3 do
    print("Hello")
end

This prints Hello three times.

Read the first line as "for i going from 1 to 3, do the following". The block between do and end runs once for each number. Each run of the block is called an iteration. As with if, the block is indented so that people can see what is repeated.

The loop variable counts for you

The name after for is the loop variable. Lua creates it for you (there is no local), gives it the first number, runs the block, adds 1, runs the block again, and stops after the block has run with the last number. Both ends are included.

Lua
for i = 1, 5 do
    print("3 x " .. i .. " = " .. 3 * i)
end
print("Done")

This prints the three times table from 3 x 1 = 3 to 3 x 5 = 15, and then Done once. Done is after end, so it is not part of the loop.

i is a traditional name for a counter. You can use any name: for day = 1, 7 do reads well when the numbers are days.

A third number sets the step, the amount added each time. With a negative step the loop counts down:

Lua
for i = 10, 2, -4 do
    print(i)
end

This prints 10, 6 and 2.

If the first number is already past the last, the block does not run at all: for i = 1, 0 do repeats zero times, and that is not an error.

A running total

A very common pattern: start a variable at zero before the loop, and add to it on every iteration. The variable is called a running total or an accumulator.

Lua
local total = 0
for number = 1, 3 do
    total = total + number
end
print(total)

This prints 6, which is 1 + 2 + 3. Step through the diagram to watch number and total change.

A loop variable and a running total
start / 8 ⇄ code
Line 3 runs three times. Each time, number has the next value and total grows by it. Line 5 runs once, after the loop.
A loop variable and a running total
Line 3 runs three times. Each time, number has the next value and total grows by it. Line 5 runs once, after the loop.

The line local total = 0 must be before the loop. Inside the block it would run on every iteration and make a fresh total each time.

The same pattern counts things: start local count = 0 and write count = count + 1 in the block.

Loops and input

The last number of a for can be a variable, so the user can decide how often the block runs:

Lua
io.write("How many names? ")
local count = tonumber(io.read("l"))

for i = 1, count do
    io.write("Name " .. i .. ": ")
    local name = io.read("l")
    print("Hello, " .. name .. "!")
end

With the answers 2, Ada and Sam the session is:

Text
How many names? 2
Name 1: Ada
Hello, Ada!
Name 2: Sam
Hello, Sam!

A variable made with local inside a block, such as name here, exists only until that block's end. Each iteration gets a fresh one.

while repeats until a condition becomes false

Sometimes you cannot know the number of repetitions in advance. A while loop has a condition, like an if. It tests the condition, and if it is true runs the block, then goes back and tests again. It stops the first time the condition is false.

Lua
local money = 100
local years = 0

while money < 200 do
    money = money + 30
    years = years + 1
end

print(years)

This prints 4: the savings go 130, 160, 190, 220, and after the fourth year the condition money < 200 is false.

A while loop goes back and checks again
start / 6 ⇄ code
The condition is tested before every iteration, including the first. Something in the block must change a variable in the condition, or the loop never ends.
A while loop goes back and checks again
The condition is tested before every iteration, including the first. Something in the block must change a variable in the condition, or the loop never ends.

A while loop can do a for loop's job, with more to write and more to get wrong:

Lua
local i = 1
while i <= 3 do
    print(i)
    i = i + 1
end

This prints 1, 2, 3. Use for when you can say how many times; use while when you can only say when to stop.

A loop that never ends

If nothing in the block changes the condition, it stays true for ever:

Lua
local i = 1
while i <= 3 do
    print(i)
end

This prints 1 again and again, because the line i = i + 1 is missing. A loop that cannot stop is called an infinite loop. There is no error message. On this site the program is stopped after a few seconds and reported as timed out; on your own computer, press Ctrl+C to stop it. When a program seems to hang, look for a while whose condition never changes.

Off-by-one mistakes

The commonest loop mistake is repeating once too often or once too few. It has a name: an off-by-one error. Check the first and last values every time you write a loop.

Lua
-- Meant to print the 3 times table up to 3 x 5.
for i = 0, 5 do
    print("3 x " .. i .. " = " .. 3 * i)
end

This prints six lines, starting with an unwanted 3 x 0 = 0, because the loop starts at 0 and both ends are included. for i = 1, 5 is right.

With while, the choice between < and <= decides the last iteration: while i < 3 stops before 3, while i <= 3 includes it. To check a loop, work out by hand what the first iteration and the last iteration do.

Three errors you will meet

A forgotten do.

Lua
for i = 1, 3
    print(i)
end
Text
solution.lua:2: 'do' expected near 'print'

The pattern is the same as 'then' expected: Lua reports the place where it noticed, which is the start of line 2. The missing word belongs at the end of line 1.

Using the loop variable after the loop.

Lua
for i = 1, 3 do
    print(i)
end
print(i + 1)
Text
/usr/bin/lua: solution.lua:4: attempt to perform arithmetic on a nil value (global 'i')
stack traceback:
	solution.lua:4: in main chunk
	[C]: in ?

The program prints 1, 2, 3 and then stops on line 4. The loop variable exists only inside the loop. After end, the name i refers to nothing. If you need a value after the loop, keep it in a variable that you created before the loop, as the running total does.

You would see almost the same message, naming total, if you forgot the line local total = 0 before a running-total loop.

Changing the loop variable.

Lua
for i = 1, 5 do
    i = i * 2
    print(i)
end
Text
solution.lua:2: attempt to assign to const variable 'i'

"Const" is short for constant: something that may not be changed. The for loop is in charge of its own counter, and Lua does not let the block assign to it. Work out the value you want in a new variable instead: local double = i * 2.

What you can do now

You can repeat a block a fixed number of times with for, count up or down, keep a running total, repeat with while until a condition changes, and check a loop's first and last iteration for off-by-one mistakes. In the exercises you will trace loops by hand and then write a program that adds up as many numbers as the user asks for.

Next: write functions and finish a complete program.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Starts at 'Looping' (19:11) with the while loop; the counting 'For' loop follows at 22:00. The short 'Repeat Until' part between them and 'For In' (22:29) show loops this unit does not use; skip them for now.