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`?
answer
- downTo = descending, step -1 by default
- step n must be positive; sign from direction
- step/downTo => IntProgression, not IntRange
- last is snapped to actual final element
- 10 downTo 1 step 3 -> 10,7,4,1
basics
~10 sstep 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.
solid answer
~40 s`downTo` is an infix function that builds an IntProgression with a negative step (-1 by default) counting from a higher start to a lower bound. `step` is an infix function that returns a new IntProgression with the given magnitude, keeping the original direction's sign. Both return IntProgression, not IntRange (only the plain `..` with step 1 is an IntRange). For `10 downTo 1 step 3`: `first = 10`, `step = -3`, and `last` is the highest value reachable from first by adding step that does not pass the bound — here 10, 7, 4, 1, so `last = 1`. The progression's `last` is computed (via getProgressionLastElement) so it always equals the actual final iterated value, which may not equal the bound you wrote.
code
kotlin · 10 linesval p = 10 downTo 1 step 3
println(p.first) // 10
println(p.last) // 1
println(p.step) // -3
for (i in p) print("$i ") // 10 7 4 1
println((1..11 step 3).last) // 10, not 11 (snapped)
// step 0 throws IllegalArgumentException
// val bad = 1..10 step 0go deeper
Knows downTo counts down and step changes the jump size; can enumerate 10,7,4,1.
Explains both return IntProgression, step must be positive, and the default steps (+1/-1).
Knows last is snapped via getProgressionLastElement and that the progression isn't a ClosedRange for membership.
Discusses why direction/sign are decoupled from step magnitude and the API safety of forcing positive step values.
## downTo and step are functions, not operators - `downTo` is an **infix extension function**: `10 downTo 1` returns an `IntProgression` with `first = 10`, `last = 1`, `step = -1`. There is no `..`-style operator for descending ranges; you must use `downTo`. - `step` is an **infix function** on a progression: `progression step n` returns a *new* `IntProgression` with the same direction but step magnitude `n`. `n` must be **positive**; the function applies the original sign. Passing `0` or a negative `n` throws `IllegalArgumentException`. ```kotlin val up = 1..10 step 2 // IntProgression: 1,3,5,7,9 (step +2) val down = 10 downTo 1 step 3 // IntProgression: 10,7,4,1 (step -3) ``` ## Type changes Only `a..b` (step 1, ascending) is an `IntRange`. The moment you apply `step` or use `downTo`, you get an `IntProgression` (the supertype). This matters because `IntProgression` is **not** a `ClosedRange`, so a stepped progression does not support `in`-membership the same way a range does — you'd be checking iteration, not interval containment. ## How last is computed The written bound is not necessarily the last element. The constructor calls an internal `getProgressionLastElement(first, last, step)` to snap the bound to the **last value actually reachable** from `first` by repeatedly adding `step`: ```kotlin val p = 1..10 step 3 // 1,4,7,10 -> last = 10 val q = 1..11 step 3 // 1,4,7,10 -> last = 10 (NOT 11) println(q.last) // 10 ``` For `10 downTo 1 step 3`: values are 10, 7, 4, 1; `first = 10`, `step = -3`, `last = 1`. ## Iteration order and reversed() `IntProgression` iterates from `first` toward `last`. `reversed()` returns a new progression with swapped ends and negated step, so `(1..5).reversed()` is `5 downTo 1`. ## Key takeaways - `downTo` and `step` both yield `IntProgression`, never `IntRange`. - `step` magnitude must be positive; the sign comes from direction. - `last` is the snapped final element, possibly different from the written bound.
- Can you pass a negative number to `step`?No. `step` requires a positive magnitude and throws IllegalArgumentException otherwise; direction is determined by `..` vs `downTo`, not by the step's sign you pass.
- Is `1..11 step 3` last 11 or 10?10 — the bound is snapped to the last element actually reachable by adding the step from first.
saying these in an interview costs you the question
- Saying `step` accepts a negative number to reverse direction
- Claiming `10 downTo 1 step 3` is still an IntRange
- Assuming `last` always equals the written upper/lower bound
- Thinking `downTo` is an operator like `..`
- Forgetting `step 0` throws