skip to content

IntRange & Progressions

IntRange and friends are closed ranges, while progressions carry a first, last, and step and are what a stepped or descending range actually produces. Both are Iterable, which is why they work directly in a for loop.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What is an IntRange in Kotlin, and how does it relate to IntProgression? How do you iterate one in a for-loop?

level: juniorimportance: must knowfreq 70%

answer

  1. IntRange = inclusive [first, last], step always 1
  2. IntRange extends IntProgression
  3. Progression = first, last, step; Iterable<Int>
  4. .. is rangeTo; for (i in 1..10)
  5. Long/CharRange are the siblings

basics

~20 s

An IntRange is a span of integers from a start to an end value, like 1 to 10. You can loop over it with a for-loop, and each step it gives you the next number.

solid answer

~30 s

An IntRange represents a closed (inclusive) range of Int values defined by a start and endInclusive bound, created with the `..` operator or `rangeTo`. It is a subtype of IntProgression, which adds a `step` (default 1) and exposes `first`, `last`, and `step`. Because IntProgression implements `Iterable<Int>`, an IntRange can be used directly in a for-loop: `for (i in 1..10) { ... }`. Iteration yields first, first+step, ... up to and including last. IntRange also implements `ClosedRange<Int>` (and `OpenEndRange<Int>`) so it supports `contains`/`in`. Sibling LongRange and CharRange behave the same for Long and Char.

code

kotlin · 11 lines
kotlin
val range: IntRange = 1..10
println(range.first)  // 1
println(range.last)   // 10
println(range.step)   // 1

// IntRange IS an IntProgression
val p: IntProgression = range

for (i in 1..5) print(i)  // 12345

println((5..1).isEmpty()) // true: start > end

go deeper

for a junior

Knows .. makes an inclusive range and that you loop with for (i in 1..10).

for a middle

Explains IntRange extends IntProgression and that first/last/step exist with step defaulting to 1.

for a senior

Notes IntRange also implements ClosedRange/OpenEndRange, that the loop is often allocation-free, and that 5..1 is empty.

for a principal

Can reason about the dual interface inheritance (progression Iterable + ClosedRange membership) and the compiler loop-lowering optimization implications.

## What an IntRange is An `IntRange` is a Kotlin standard-library type representing a **closed (inclusive) interval** of `Int` values: it has a start and an `endInclusive`, both included. You create one most often with the `..` range operator, which is sugar for the `rangeTo` function: ```kotlin val r: IntRange = 1..10 // 1, 2, ..., 10 (both ends included) println(r.first) // 1 println(r.last) // 10 println(r.step) // 1 ``` ## Relationship to IntProgression The class hierarchy is the key idea: - `IntProgression` is an **arithmetic progression** of `Int`s defined by three numbers: `first`, `last`, and `step` (a non-zero step). It implements `Iterable<Int>`. - `IntRange` is a **subclass** of `IntProgression` whose `step` is always `1`. It *also* implements `ClosedRange<Int>` and `OpenEndRange<Int>`, which is what gives it `contains`/membership semantics. So every `IntRange` is an `IntProgression`, but not every progression is a range. A `2..10 step 2` produces an `IntProgression` (step 2), not an `IntRange`. ## Iterating in a for-loop Because `IntProgression` implements `Iterable<Int>`, you can put a range directly after `in`: ```kotlin for (i in 1..5) print(i) // 12345 ``` The compiler frequently **optimizes** `for (i in a..b)` into a plain counting loop with no allocation or iterator object, but semantically it iterates `first`, `first + step`, ... while the value has not passed `last`. ## Other range types - `LongRange` / `LongProgression` — same shape for `Long`. - `CharRange` / `CharProgression` — same shape for `Char`, e.g. `'a'..'z'`. ## Empty ranges If the start is greater than the end (with a positive step), the range is **empty**: `(5..1).isEmpty()` is `true`, and the for-loop body never runs. `IntRange.EMPTY` is a canonical empty instance. ## Key takeaways - `..` creates an inclusive `IntRange`. - `IntRange` extends `IntProgression`; progressions carry `first`, `last`, `step`. - Progressions are `Iterable`, so they work in for-loops, often without allocation.

  • Is 1..10 inclusive or exclusive of 10?
    Inclusive — IntRange is a closed range, so both 1 and 10 are produced. Use 1 until 10 (or 1..<10) for an exclusive upper bound.
  • What's the type of 2..10 step 2?
    IntProgression, not IntRange, because the step is no longer 1.

A progression is like setting a metronome (start, end, tick interval); an IntRange is that metronome locked to a tick of 1.

saying these in an interview costs you the question

  • Saying IntRange is exclusive of the upper bound
  • Claiming IntRange and IntProgression are unrelated types
  • Thinking a for-loop over a range always allocates an iterator object
  • Confusing `..` (rangeTo) with `until` semantics
  • Believing 5..1 throws instead of being empty

context

open as a page

How do `step` and `downTo` change the type and iteration of a range? What are first, last, and step after `10 downTo 1 step 3`?

level: middleimportance: must knowfreq 60%

basics

~10 s

step changes how far each jump is, and downTo counts backwards. Together they make a progression that goes down. For 10 downTo 1 step 3 you get 10, 7, 4, 1.

open as a page

How do CharRange and LongRange differ from IntRange, and how does iterating `'a'..'z'` work under the hood?

level: middleimportance: should knowfreq 40%

basics

~10 s

CharRange spans characters like 'a' to 'z', and LongRange spans large whole numbers. They work just like IntRange but for those types, and looping over 'a'..'z' gives each letter in order.

open as a page

IntProgression implements Iterable<Int>, yet `for (i in 0..n)` rarely allocates. Explain how iteration works and when the compiler optimization does or doesn't kick in.

level: seniorimportance: should knowfreq 35%

basics

~20 s

A progression knows how to hand out numbers one by one through an iterator. But when you write a simple for-loop over a literal range, the compiler turns it into a plain counting loop with no extra objects, so it's fast.

open as a page

How are IntProgression equality, emptiness, and the `last` value defined? Why might two differently-written ranges be equal, and when is a progression empty?

level: seniorimportance: nice to knowfreq 22%

basics

~10 s

A progression is empty when it would produce no numbers (start past end for its direction). Two progressions count as equal when they're both empty, or when their start, end, and step all match.

open as a page