What does Kotlin's `for (x in something)` loop actually require of `something`, and how does it relate to `Iterable` and `Iterator`?
answer
- for-in = sugar for iterator()/hasNext()/next()
- operator funs, can be extensions
- iterator() called once per loop
- Iterable declares iterator(), Iterator declares hasNext/next
- Collection : Iterable
basics
~10 sA for loop works on anything that has an iterator() function. That function returns an iterator with hasNext() and next(), which the loop calls repeatedly to walk through the elements.
solid answer
~40 sKotlin's `for (x in c)` is syntactic sugar. The compiler requires `c` to provide an `operator fun iterator()` returning an object with `operator fun hasNext(): Boolean` and `operator fun next(): T`. `Iterable<T>` is the standard interface declaring `iterator(): Iterator<T>`, and `Iterator<T>` declares `hasNext()`/`next()`. But you don't strictly need to implement `Iterable`; any type with those `operator` functions (even via extension functions) becomes loop-able. The loop desugars to: create the iterator once, then `while (it.hasNext()) { val x = it.next(); ... }`. Arrays, ranges (`IntRange`), strings, and `Sequence` are iterable through this same protocol. This convention-based design is why `0..10`, a `CharSequence`, and a custom class can all share one loop syntax.
code
kotlin · 9 linesclass Countdown(val from: Int) {
operator fun iterator() = object : Iterator<Int> {
var current = from
override fun hasNext() = current >= 0
override fun next() = current--
}
}
for (n in Countdown(3)) print("$n ") // 3 2 1 0go deeper
Knows for walks elements and that there's an iterator() with hasNext()/next().
Can describe the exact desugaring and that the functions are operator and can be extensions.
Explains the convention-vs-interface distinction, why Iterable unlocks stdlib operators, and iterator state/lifetime.
Discusses designing APIs around the protocol, variance (out T), and trade-offs of operator-convention vs. nominal Iterable for library ergonomics.
## The `for` loop is a convention, not a hard interface Kotlin has no built-in `for`-each tied to a single type. Instead, `for (x in c) { ... }` is **desugared by the compiler** into iterator calls. For this to compile, `c` must expose three `operator` functions: - `operator fun iterator(): I` — returns an iterator object. - `I.operator fun hasNext(): Boolean` — is there another element? - `I.operator fun next(): T` — return the next element and advance. These can be **members** or **extension functions**. That's why you can make a third-party type loop-able by writing an extension `operator fun Foo.iterator()`. ## The standard interfaces The stdlib formalizes the common case: ```kotlin public interface Iterable<out T> { public operator fun iterator(): Iterator<T> } public interface Iterator<out T> { public operator fun next(): T public operator fun hasNext(): Boolean } ``` `Collection<T>` (and thus `List`, `Set`) extends `Iterable<T>`. So every collection is loop-able for free. ## How the loop desugars ```kotlin for (x in c) { use(x) } // becomes roughly: val it = c.iterator() while (it.hasNext()) { val x = it.next() use(x) } ``` Key consequences: - `iterator()` is called **once** per loop — the same iterator drives the whole loop. - `next()` should be called only after `hasNext()` returns `true`; otherwise the iterator typically throws `NoSuchElementException`. - The iterator holds the **traversal state** (cursor position), so the source collection stays stateless across iterations. ## Why this matters Because it's convention-based, `IntRange` (`0..10`), `CharSequence`, arrays, maps' entry sets, and your own classes can all be looped with identical syntax. You implement `Iterable<T>` when you want your type to be a first-class collection-like source and to inherit all the stdlib extension operators (`map`, `filter`, `forEach`, etc.) that are defined on `Iterable<T>`.
- Do you have to implement `Iterable` to use it in a `for` loop?No. You only need `operator fun iterator()` returning an object with `operator hasNext()`/`next()`. These can be extension functions, so even a type you don't own can be made loop-able.
- What free functionality do you gain by implementing `Iterable<T>` instead of just `operator iterator()`?All stdlib extensions on `Iterable<T>` — `map`, `filter`, `forEach`, `sumOf`, `groupBy`, etc. — plus interoperability anywhere an `Iterable` is expected.
An iterator is like a bookmark that walks a book page by page: hasNext() checks for another page, next() reads it and moves the bookmark forward.
saying these in an interview costs you the question
- Claiming `for` requires implementing `Iterable` (the operator convention is enough)
- Saying `iterator()` is called every loop pass rather than once
- Calling `next()` without `hasNext()` and not knowing it throws `NoSuchElementException`
- Confusing `hasNext()` with consuming the element (it only peeks/checks)
- Thinking `for` works on `Sequence` differently — it uses the same protocol