skip to content

Range Operators

The .. operator builds a closed range, ..< and until give you a half-open one, downTo counts backwards, and step sets the increment. Mixing up closed and half-open is a genuine off-by-one source, which is why interviewers ask.

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

questions

5

How do you create a range of integers in Kotlin, and what does the `..` operator produce?

level: juniorimportance: must knowfreq 78%

answer

  1. `a..b` == `a.rangeTo(b)`
  2. Inclusive on BOTH ends
  3. IntRange is an IntProgression -> iterable
  4. start > end => empty, not descending
  5. Double `..` works with `in` but not `for`

basics

~10 s

Write 1..5 to make a range from 1 to 5 including both ends. You can then loop over it with for (i in 1..5).

solid answer

~30 s

The `..` operator builds a closed (inclusive) range. `1..5` desugars to `1.rangeTo(5)` and returns an `IntRange` covering 1, 2, 3, 4, 5 — both endpoints are included. It's a `ClosedRange` and also an `IntProgression`, so it is iterable: `for (i in 1..5) { ... }` works directly. You can also test membership with `in`: `3 in 1..5` is `true`. `..` is an operator function defined via `operator fun rangeTo`, available on `Int`, `Long`, `Char`, and other `Comparable` types. For non-iterable comparables (like `Double` or `String`) `..` still creates a `ClosedRange` usable with `in`, but you cannot iterate it.

code

kotlin · 5 lines
kotlin
val r: IntRange = 1..5
println(r.toList())   // [1, 2, 3, 4, 5]
println(r.first)       // 1
println(r.last)        // 5
println((5..1).isEmpty()) // true (does NOT count down)

go deeper

for a junior

Knows 1..5 is inclusive both ends and loops with for (i in 1..5).

for a middle

Explains .. desugars to rangeTo, returns IntRange (a progression), and that 5..1 is empty not descending.

for a senior

Distinguishes ClosedRange vs IntProgression, knows Double ranges are non-iterable, and the in membership semantics.

for a principal

Frames .. as an overloadable operator (operator fun rangeTo) usable on custom Comparable types, and reasons about the range/progression type hierarchy.

## The `..` operator In Kotlin, `a..b` is the **range** operator. It is shorthand for the operator function call `a.rangeTo(b)`. For integers it produces an **`IntRange`** — an inclusive (closed) interval that contains every value from `a` to `b`, **both endpoints included**. ```kotlin val r = 1..5 // IntRange: 1, 2, 3, 4, 5 val same = 1.rangeTo(5) // identical — .. is sugar for rangeTo ``` ## What you get back - `1..5` is an `IntRange`, which is a subtype of `IntProgression` (an arithmetic sequence with a step, default `1`) and of `ClosedRange<Int>`. - Because it is a progression, it is **iterable** — you can use it in a `for` loop. - Because it is a `ClosedRange`, you can use the **`in`** operator for membership tests. ```kotlin for (i in 1..5) print(i) // 12345 println(3 in 1..5) // true println(6 in 1..5) // false ``` ## Endpoints and empty ranges `..` is **inclusive on both ends**. If the start is greater than the end, the range is **empty** (it iterates zero times) — `5..1` produces nothing in a `for` loop and `isEmpty()` returns `true`. It does *not* throw and does *not* count down; to count down you need `downTo`. ## Types it works on `rangeTo` is defined for `Int`, `Long`, `Char`, and any `Comparable`. For `Char`, `'a'..'f'` is a `CharRange`. For non-integral comparables like `Double` or `String`, `..` makes a `ClosedRange` you can test with `in` but **cannot iterate**, because there is no natural integer step. ```kotlin println(0.5 in 0.0..1.0) // true — works // for (x in 0.0..1.0) ... // does NOT compile: not iterable ``` ## Related operators (same family) - `..<` / `until` — half-open (excludes the end). - `downTo` — descending range. - `step` — change the increment.

  • Is `1..5` inclusive or exclusive of 5?
    Inclusive — it contains 5. Use `1..<5` or `1 until 5` to exclude it.
  • What happens with `5..1` in a for loop?
    Nothing iterates — it's an empty range. Use `5 downTo 1` to descend.
  • Can you iterate `0.0..1.0`?
    No. Double ranges support `in` membership but are not progressions, so they are not iterable.

Like a guest list from seat 1 to seat 5 — both the first and last seats are on the list.

saying these in an interview costs you the question

  • Thinking `..` excludes the upper bound
  • Believing `5..1` counts down
  • Claiming you can `for`-loop over a `Double` range
  • Saying `..` returns a `List` rather than a lazy range/progression

context

open as a page

How do you build a descending range and how do you change the increment? Explain `downTo` and `step`.

level: middleimportance: must knowfreq 64%

basics

~10 s

Use downTo to count down, like 5 downTo 1. Use step to skip values, like 0..10 step 2 for 0,2,4,6,8,10. You can combine them: 10 downTo 0 step 2.

open as a page

What is the difference between `..` and `..<` / `until`, and when would you reach for the half-open form?

level: middleimportance: must knowfreq 70%

basics

~10 s

.. includes the last value; ..< (and the older until) stops just before it. Use the half-open form for index loops like 0..<list.size so you don't run off the end.

open as a page

What are the operator-precedence and edge-case pitfalls when writing range expressions like `0..n-1`, `1..count step 2`, or negative steps?

level: seniorimportance: should knowfreq 33%

basics

~20 s

.. binds tighter than +/- is a myth — actually +/- bind tighter, so 0..n-1 works as expected. But .. binds tighter than infix step/downTo calls, and a wrong or negative step throws at runtime, not compile time.

open as a page

What operator functions back `..`, `..<`, `downTo`, and `step`, and what does that imply for using them on your own or non-Int types?

level: seniorimportance: should knowfreq 40%

basics

~10 s

.. calls rangeTo, ..< calls rangeUntil; downTo and step are infix library functions. Because .. and ..< are operators, you can define them on your own Comparable types to support in checks.

open as a page