Skip to content
Lesson 8 of 19

Step 1 of 5 · Reading · ~3 min

Learn

Control Flow

Loops and Ranges

Kotlin's for loop does exactly one thing: it walks over something. There is no for (i = 0; i < n; i++) form at all. What you walk over is usually a range.

Building ranges

ExpressionProducesNote
1..51 2 3 4 5both ends included
1 until 51 2 3 4upper end excluded
5 downTo 15 4 3 2 1counts backwards
0..10 step 20 2 4 6 8 10any stride
5..1nothing at allan empty range, not an error
fun main() {
    for (i in 1..3) print(i)
    println()
    for (i in 1 until 3) print(i)
    println()
    for (i in 3 downTo 1) print(i)
    println()
    for (i in 5..1) print(i)
    println("(empty)")
}

//> 123
//> 12
//> 321
//> (empty)

That last one is worth remembering. 5..1 does not quietly count downwards and does not throw — it produces nothing, so the loop body never runs even once. If you want to go down, you have to say downTo.

✓ / ✗ — the off-by-one

This is the single most common loop bug in Kotlin, because both forms read naturally in English.

✓ Sum of 1 through n, inclusive:

for (i in 1..n) total += i

✗ Stops one short — n itself is never added:

for (i in 1 until n) total += i

Rule of thumb: until is for indexes, which stop one before the size. .. is for values you were handed.

Walking a collection

fun main() {
    val crew = listOf("Ada", "Grace", "Alan")

    for (name in crew) println(name)
    for (i in crew.indices) println(i)
    for ((i, name) in crew.withIndex()) println("$i -> $name")
}

//> Ada
//> Grace
//> Alan
//> 0
//> 1
//> 2
//> 0 -> Ada
//> 1 -> Grace
//> 2 -> Alan

crew.indices is exactly 0 until crew.size, which is a good reminder of why until is the right tool for indexes.

while and do-while

while tests before the body runs; do-while runs the body once and tests afterwards, so it always executes at least one time.

fun main() {
    var countdown = 3
    while (countdown > 0) {
        print(countdown)
        countdown -= 1
    }
    println("go")
}

//> 321go

Note the var. A counter or an accumulator is the honest use of var — a val cannot be reassigned, so total += i on a val will not compile.

The library shortcut

Ranges and lists are ordinary values, so the standard library functions apply to them too:

fun main() {
    println((1..5).sum())
    println((1..5).count())
}

//> 15
//> 5

You will meet map, filter and the rest properly in the Lambdas and Higher-Order Functions lesson. For now it is enough to know that sum() on a range exists and does what it says.

Your exercise

Sum 1 to N reads a positive integer and prints 1 + 2 + ... + n.

Either write the loop with a var total = 0 accumulator or call (1..n).sum() — both are fine, and both are worth writing once. The mistake the grader catches is the off-by-one: the first visible test feeds 5 and expects 15, but for (i in 1 until n) stops at 4 and prints 10. A hidden test feeds 100 and expects 5050, so the answer has to be computed rather than hardcoded. Print the total alone, with no surrounding text.

Up nextFunctionsFunctions and Lambdas

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…