What an infinite loop is
A while loop repeats its body for as long as its condition is true. If nothing inside the body can ever make the condition false, the loop never ends. That is an infinite loop: the program keeps running, usually printing the same thing again and again, and never reaches the code after the loop.
The classic cause is forgetting to update the variable the condition depends on:
var i = 1
while (i < 5) {
println(i)
// forgot i++ here
}
The variable i starts at 1 and never changes, so i < 5 is true on every check. The program prints 1 forever. A loop like this makes a program unusable, so every loop you write needs a path to a false condition.
Three questions to ask about any while loop
- What does the condition depend on? Name the variable, or variables, it reads.
- Does the body change them? If no statement in the body touches those variables, the loop cannot end by itself.
- Do they change in the right direction? A counter that must reach a limit has to move toward that limit. A condition like
i < 5withi--in the body moves away from the limit and never stops.
A fourth cause is subtler, and it is the one this lesson's exercise is about: the variable changes in the right direction but jumps over the value the condition is waiting for.
The exercise: odd numbers from 15 down to 1
The starting program should print 15, 13, 11, and so on down to 1, and then stop:
var counter = 15
while (counter != 0) {
println(counter)
counter -= 2
}
Instead it prints the right numbers and then keeps going. Follow counter through the last few passes:
Value of counter | Is counter != 0 true? | What happens |
|---|---|---|
| 3 | yes | prints 3, becomes 1 |
| 1 | yes | prints 1, becomes -1 |
| -1 | yes | prints -1, becomes -3 |
| -3 | yes | prints -3, and so on |
Starting at 15 and subtracting 2 only ever produces odd numbers. Zero is even, so the counter steps over it, and the condition counter != 0 stays true for every value after that. The loop is waiting for an exact value that it will never hit.
Step by step
- Find the mistake. The body is fine: it prints the counter and moves it down by 2. The problem is the condition, which tests for one exact value.
- Describe the real stopping rule. The loop should run while the counter is still positive. The last value that should print is 1, and the next value, -1, should end the loop.
- Replace
!=with a comparison that checks a range.counter > 0is true for 15 down to 1 and false for -1, so the loop stops right after printing 1.
The solution in Kotlin
var counter = 15
while (counter > 0) {
println(counter)
counter -= 2
}
The output is 15, 13, 11, 9, 7, 5, 3, 1, each on its own line, and then the program continues past the loop.
A few Kotlin details here:
varis required. Avalcannot be reassigned, socounter -= 2only compiles becausecounteris declared withvar.counter -= 2is shorthand forcounter = counter - 2.- Whole numbers wrap, they do not stop. A Kotlin
Inthas 32 bits. If a loop kept counting up pastInt.MAX_VALUE(2147483647), the value would wrap around to the most negative number instead of failing. This can turn a loop that "should" end into one that runs for a very long time.
Why a range check is safer than an exact match
Comparing with != or == works only when the counter is certain to land on the target value. That depends on the starting value, the step and the target all lining up, and a small change to any of them breaks it. For example, with counter != 0 the loop stops if the start is 16 (16, 14, ... 2, 0) but runs forever if the start is 15. Conditions that use <, <=, > or >= ask "have we gone far enough?", and they stay correct when the counter jumps past the limit.
Other common ways to loop forever
- Updating the wrong variable. The body changes
jwhile the condition readsi. - Moving in the wrong direction.
i++in a loop that waits forito fall below a limit. - Update behind a condition. The step lives inside an
ifthat is sometimes false, so on some passes the counter does not change. - A condition that is always true.
while (true)is a loop without an end on purpose. It is only correct when something inside the loop, such as abreak, can leave it.
What to do when a program will not stop
Stop the program, then read the loop with a pencil: write the variable's value for the first three passes and the last few passes you expect. Add a temporary println of the variables the condition reads. If the printed values never approach the limit, or step over it, you have found the cause.
Key takeaways
- An infinite loop is a loop whose condition never becomes false.
- The loop body must change something the condition reads, and change it toward making the condition false.
- Prefer range conditions (
>,<,>=,<=) over exact matches (!=,==) so a step that skips a value cannot hang the loop. - Here,
counter != 0becamecounter > 0, and the loop now ends after printing 1.