CLOVIS
12/13/2025, 9:33 PMIntProgression is quite inconvenient to work with…
To model progressions that can be open-ended, I use 0 as a minimum and Int.MAX_VALUE as a maximum. However, when querying an actual list, I don't want to iterate over all the values larger than the array items. For example:
val range = 5..Int.MAX_VALUE
val list = listOf(...)
for (index in range) {
if (index in list.indices) {
...
}
}
is very wasteful, because almost all values from range won't be in list.indices .
I expected to be able to write:
for (index in range.coerceIn(list.indices)) {
...
}
but this function doesn't exist.
But it's also not convenient because I can't just copy an existing progression, as:
val p = 5 downTo 2 step 2
val p2 = p.first .. p.last step p.step
is illegal, as the step function only allows positive steps (even though the progression does store it as negative).
So far my best one is
val normalizedRange = IntProgression.fromClosedRange(
rangeStart = range.first.coerceIn(elements.indices),
rangeEnd = range.last.plus(if (range.step > 0) 1 else -1).coerceIn(elements.indices),
step = if (range.step > 0) range.step else -range.step,
)
but that's quite verbose (and I'm not sure it's correct)Youssef Shoaib [MOD]
12/14/2025, 2:30 AMCLOVIS
12/14/2025, 3:03 PMephemient
12/14/2025, 5:17 PM.. ≅ (Unbounded, Unbounded)
1.. ≅ (Included(1), Unbounded)
..5 ≅ (Unbounded, Excluded(5))
..=4 ≅ (Unbounded, Included(4))
1..5 ≅ (Included(1), Excluded(5))
1..=4 ≅ (Included(1), Included(4))
can express many types of ranges (and while there's no dedicated syntax for a range with an excluded start bound, it's possible by just writing the tuple). then when you use a range to slice a vector or array, any unbounded ends are clamped to the first or last index. I wish we had something like that instead of just ad-hoc ClosedRange and OpenEndRangeephemient
12/14/2025, 5:19 PMephemient
12/14/2025, 5:20 PMstep is involved… I haven't tested your code but rangeStart doesn't look right for negative steps