skip to content

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

level: middleimportance: must knowfreq 64%

answer

  1. `downTo` to descend; `..` never counts down
  2. `step` must be POSITIVE (even descending)
  3. Direction from downTo, magnitude from step
  4. `last` recomputed to last reachable value
  5. No `..<` for descending — use downTo

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.

solid answer

~40 s

Descending iteration uses the infix function `downTo`: `5 downTo 1` yields 5,4,3,2,1 (inclusive, step -1). Plain `..` never counts down — `5..1` is empty. To change the increment, chain the infix `step` function with a **positive** value: `0..10 step 2` -> 0,2,4,6,8,10. `step` always takes a positive int even for descending progressions; the direction comes from `downTo`, so `10 downTo 0 step 3` -> 10,7,4,1. Both return an `IntProgression` (or `LongProgression`/`CharProgression`). The `last` value is recomputed to the largest reachable value that fits the step — e.g. `0..10 step 3` ends at 9, not 10. Passing a non-positive `step` throws `IllegalArgumentException`. There is no `..<` operator for descending; combine `downTo` with `step` instead.

code

kotlin · 5 lines
kotlin
println((10 downTo 0 step 2).toList()) // [10, 8, 6, 4, 2, 0]
println((0..10 step 3).last)            // 9, not 10
try { 1..10 step -1 } catch (e: IllegalArgumentException) {
    println(e.message) // Step must be positive...
}

go deeper

for a junior

Can write 5 downTo 1 and 0..10 step 2 and read the output.

for a middle

Explains step must be positive, direction comes from downTo, and combining the two.

for a senior

Knows last is recomputed to the last reachable value and that these return IntProgression; handles the IllegalArgumentException contract.

for a principal

Reasons about progression internals (first/last/step normalization), Long/Char variants, and why an exclusive descending operator was intentionally omitted.

## Descending: `downTo` The `..` operator only goes **up**, so `5..1` is an *empty* range. To iterate downward, use the infix standard-library function **`downTo`**: ```kotlin for (i in 5 downTo 1) print(i) // 54321 println((5 downTo 1).toList()) // [5, 4, 3, 2, 1] ``` `downTo` is **inclusive** on both ends and uses a default step of **-1**. It returns an `IntProgression` (an arithmetic sequence start..end with a step). ## Changing the increment: `step` `step` is an infix function that sets the **magnitude** of the increment. It must be **strictly positive**, regardless of direction: ```kotlin println((0..10 step 2).toList()) // [0, 2, 4, 6, 8, 10] println((10 downTo 0 step 3).toList()) // [10, 7, 4, 1] ``` The direction (ascending/descending) is decided by `..`/`until`/`downTo`; `step` only changes the size of each jump. Calling `step` with `0` or a negative number throws: ```kotlin 0..10 step -2 // IllegalArgumentException: Step must be positive, was: -2. ``` ## How `last` is adjusted A progression stores `first`, `last`, and `step`. When you apply a `step` that doesn't divide the span evenly, Kotlin recomputes `last` to the **last value actually reachable**: ```kotlin val p = 0..10 step 3 // 0, 3, 6, 9 println(p.last) // 9 (NOT 10 — 10 is unreachable from 0 by +3) ``` This means `p.last` may differ from the bound you wrote. Membership and iteration both respect the corrected `last`. ## Combining the operators You can stack them. Precedence: `..`/`downTo`/`until` bind first, then `step`: ```kotlin 100 downTo 0 step 25 // 100, 75, 50, 25, 0 0..<10 step 3 // 0, 3, 6, 9 (half-open then stepped) ``` There is **no** `..<`-style descending operator; for an exclusive lower-bound descent, adjust the endpoint manually (e.g. `10 downTo 1` to exclude 0). ## Types `downTo` and `step` exist for `Int`, `Long`, and `Char`, returning `IntProgression`, `LongProgression`, and `CharProgression` respectively.

  • Why doesn't `step` take a negative number for descending ranges?
    Direction is already encoded by `downTo`. `step` only sets the magnitude and is validated to be positive; a negative value throws IllegalArgumentException.
  • What is `(0..10 step 3).last`?
    9 — the last value reachable from 0 by +3 within the bound; `last` is recomputed, not the literal 10.
  • How do you make a half-open descending range?
    There's no `..<` for descent; adjust the endpoint, e.g. `10 downTo 1` to exclude 0.

Walking down stairs (downTo) two steps at a time (step 2) — you always step a positive number of stairs; the 'down' is the direction you face.

saying these in an interview costs you the question

  • Using `5..1` and expecting it to count down
  • Passing a negative value to `step`
  • Assuming `(0..10 step 3).last == 10`
  • Inventing a descending `..<` operator

context