Learning Kotlin: The For Loop

Note This is the 20th post in a multipart series. If you want to read more, see our series index.


Kotlin has two loops: while and for. When I started, I was like, "yup, I know those..."—except I didn’t. while works the way I expected it would, but for is something else. First, Kotlin doesn’t have a traditional for loop, like for (var i = 0; i < max; i++). Instead, the for loop in Kotlin is closer to the iterator foreach loop in C#.

Basic

Let’s start with the basics: how do I run a loop, say, 10 times, where we print out 0, 1, 2, 3, 4, 5, 6, 7, 8, 9?

fun main(args: Array<String>) {
    for (i in 0..9) {
        println(i)
    }
}

In this example, we use a ClosedRange (0..9) to state the start and end of the loop. This is equivalent to for (var i = 0; i < 10; i++).

Now, normally we want to loop over an array of items, and we can do this in two ways. First, the equivalent of C#’s for iterator or JavaScript’s for...of:

fun main(args: Array<String>) {
    val a = arrayOf("The", "Quick", "Brown", "Fox")
    for (i in a) {
        println(i)
    }
}

And if we use the older style of a normal for loop with an index:

fun main(args: Array<String>) {
    val a = arrayOf("The", "Quick", "Brown", "Fox")
    for (i in 0 until a.size) {
        val value = a[i]
        println(value)
    }
}

What’s awesome here is the Range. Unlike the inclusive bounds of .., the until keyword gives us an exclusive upper bound.

Kotlin is all about helpers, and since we looked at destructuring last time, it shouldn’t be a surprise that we can use it to include both the index and the value in the for loop:

fun main(args: Array<String>) {
    val a = arrayOf("The", "Quick", "Brown", "Fox")
    for ((i, value) in a.withIndex()) {
        println("$i is $value")
    }
}

Extras

The for loop has two additional options worth knowing:

Operator Overloading

Adding support for this to our own classes is trivial—just add the Iterator interface. This introduces two methods:

Let’s implement this with a PrimeNumbers class. Since there are infinite primes, we’ll add a top bound (maxToHunt), which forces the loop to eventually end. In next(), we not only return the current prime but also calculate the next next value to efficiently track whether more primes exist.

class PrimeNumbers : Iterator<Int> {
    var currentPrime = 1
    val maxToHunt = 100
    var morePrimesToFind = true

    override fun next(): Int {
        val result = this.currentPrime
        this.currentPrime += 1
        while (this.currentPrime < this.maxToHunt) {
            var primeFound = true
            for (divisor in this.currentPrime - 1 downTo 2) {
                if (this.currentPrime % divisor == 0) {
                    this.currentPrime += 1
                    primeFound = false
                    break
                }
            }
            if (primeFound) break
        }
        this.morePrimesToFind = this.currentPrime < this.maxToHunt
        return result
    }

    override fun hasNext() = this.morePrimesToFind
}

fun main(args: Array<String>) {
    for (i in PrimeNumbers()) {
        println("$i is prime")
    }
}