Pocket Studio Academy
HomePart 11.7

Loops — while, for and ranges

Free lesson10 min read·4 questions

Computers are astonishingly good at doing the same thing again. Learn while for "keep going until", for for "do this to each of these", and the two-dot-versus-until difference that causes more bugs than anything else in this part.

Nobody types the same line a hundred times

Suppose you want to print the numbers 1 to 100. You could write a hundred println lines. It would work. It would also take five minutes, contain at least one typo, and be unusable the moment somebody says "actually, make it 500".

A is code that repeats. You write the repeated part once and say how many times, or under what condition, to go round.

kotlin
1for (i in 1..100) {
2  println(i)
3}

Three lines. Change the 100 to 500 and you are done.

Think of it like this

Think about walking up a staircase.

There are two ways to describe the climb. You can say "keep going up while there are still steps left" — you do not know how many there are, you just check each time whether you have reached the top.

Or, if you counted them on the way down yesterday, you can say "take twelve steps" — a fixed number, decided before you start.

Kotlin has both. is the first one: keep going while something is true. is the second: walk through a known set of things, one at a time, and stop by itself at the end.

while — keep going until something changes

kotlin
1var lives = 3
2while (lives > 0) {
3  println("Lives: $lives")
4  lives = lives - 1
5}
6println("Game over")

That prints Lives: 3, Lives: 2, Lives: 1, then Game over.

The in the brackets is checked before every pass, including the very first one. If it is false to begin with, the body never runs at all — a while can run zero times, and that is often exactly what you want.

Careful

Something inside the loop must eventually make the condition false. Delete the lives = lives - 1 line above and lives stays at 3 forever. That is an : the program does not crash, it just never finishes, and the Output panel fills with identical lines until you press Stop.

If a program seems to hang, an infinite loop is the first thing to suspect. Check that whatever the condition tests is actually changed somewhere inside the body.

for and ranges — walk through a known set

When you do know what to walk through, for is safer, because it cannot forget to stop:

kotlin
1for (i in 1..5) {
2  println(i)
3}

Read for (i in 1..5) as "for each number i in one to five". Each time round, i holds the next value. That prints 1, 2, 3, 4, 5.

1..5 is a . And here is the thing to burn into memory:

Two dots include both ends. 1..5 is five numbers: 1, 2, 3, 4 and 5.

The one that catches everybody

Now the counterpart:

kotlin
1for (i in 0 until 5) {
2  println(i)
3}

That prints 0, 1, 2, 3, 4. Five numbers again — but it stops before the 5.

excludes its end value. Two dots include it. That single difference is the source of the , the most common counting bug in all of programming, and you will meet it for real in Lesson 1.10 when lists start at position 0.

Put the two side by side and say them out loud:

WrittenGivesCount
1..51, 2, 3, 4, 55 numbers
1 until 51, 2, 3, 44 numbers
0..50, 1, 2, 3, 4, 56 numbers
0 until 50, 1, 2, 3, 45 numbers

Two useful relatives:

kotlin
1for (i in 5 downTo 1) {
2  println(i)
3}
4for (i in 0..10 step 2) {
5  println(i)
6}

downTo counts backwards — 5, 4, 3, 2, 1. step 2 skips — 0, 2, 4, 6, 8, 10. Note that downTo also includes both ends.

Tip

When you simply want something to happen a fixed number of times and do not care about the counter, Kotlin has a shortcut:

kotlin
1repeat(3) {
2  println("Hip hip")
3}

That is three cheers with no counter to get wrong.

Stopping early, and skipping one

Two words work inside any loop:

  • break leaves the loop immediately.
  • continue skips the rest of this pass and goes round again.
kotlin
1for (i in 1..10) {
2  if (i == 4) continue
3  if (i == 7) break
4  println(i)
5}

That prints 1, 2, 3, 5, 6. Four is skipped, and at seven the loop stops for good.

The loop variable belongs to the loop

kotlin
1for (i in 1..3) {
2  println(i)
3}
4println(i)   // Unresolved reference: i

i exists only inside the loop's . Once the loop ends, so does the name. It is also a each time round, so you cannot reassign it inside the body — if you need a counter you control, use while with your own .

Four loops, stepped through

Try it in Pocket Studio
  1. Open Pocket Studio, tap Projects, open KotlinLab, then open Lab.kt.
  2. Clear the inside of main and type in the program from the walkthrough above.
  3. Tap Run. Count the lines in the Output panel. There should be twelve: three Lives, three Step, three Index, three Countdown.
  4. Change for (i in 1..3) to for (i in 1 until 3) and run again. Now there are only two Step lines. One character of difference, one fewer pass.
  5. Change for (i in 3 downTo 1) to for (i in 3..1) and run. Nothing at all is printed for that loop — 3..1 is an empty range. No error, no output. Silent bugs like this are why downTo exists.
  6. Now make one on purpose: delete the lives = lives - 1 line and press Run. The output fills endlessly with Lives: 3. Tap Stop, put the line back, and run again.
  7. Finally add println(i) after the closing bracket of the last loop, and run. Read the Unresolved reference: i error — that is doing its job.
Error Doctor5 common errors
e: Expecting 'in'
MeansThe loop is written in the older three-part style from Java or C: for (i = 0; i < 5; i++). Kotlin has no such form.
FixRewrite it as a range: for (i in 0 until 5). If you genuinely need full control of the counter, use a while loop with your own var.
e: Val cannot be reassigned
MeansYou tried to change the loop variable inside the body. In a for loop that name is a fresh val on every pass, so it cannot be assigned to.
FixIf you need to skip ahead, use step, continue, or a while loop with a var you control yourself.
e: Unresolved reference: i
MeansThe loop variable was used after the loop finished. It only exists inside the loop's block.
FixDeclare a var above the loop and update it inside, if you need the value afterwards.
e: For-loop range must have an iterator() method
MeansThe thing after in is not something Kotlin knows how to walk through — a single number, for instance, rather than a range.
FixGive it a range or a list: for (i in 1..n), not for (i in n).
The program keeps running and the Output panel never stops
MeansAn infinite loop. The condition never becomes false, so the body repeats forever. There is no error message because nothing is technically wrong.
FixTap Stop. Then look at the condition and ask which line inside the loop is meant to change it. Nine times out of ten that line is missing, or it is changing a different name.
Recap
  • A runs the same block repeatedly so you never type the same line twice.
  • repeats while a is true, checking before each pass — so it can run zero times. Something inside must change the condition, or you get an .
  • walks a and stops by itself.
  • 1..5 includes both ends. 1 until 5 stops one short. That difference is the waiting to happen.
  • downTo counts backwards, step skips, repeat(n) does something n times with no counter.
  • break leaves a loop; continue skips to the next pass.
  • Next: naming a whole block of steps so you can run it whenever you like — functions.