it's always confusing, in languages with ranges, whether the range includes the second boundary element or not. it's purely a matter of convention, after all. ruby has a..b and a...b, but even after years of using the language i have to look up which is which. a..<b and a..b is perfect notation - once you know the language handles both cases, a..<b is very clearly "the range of numbers from a, and remaining strictly less than b", and "a..b" is "the range of numbers from a up to and including b".
as for the "count - 1", it's not too bad because i find "inclusive" more intuitive than "exclusive" for the a..b notation, and that does make it explicit that you're not including b, but it's visual clutter in much the same way that having to iterate an array via "for i = 0 to len - 1" is.
You only need to know that the language handles one explicitly, since there's two choices, so you might as well take the (more common | uglier to express) case and give it the "cleanest" special syntax: no special syntax.
I always remembered it as "the third dot makes it bigger so it pushes the range and the last item falls off". I can't remember where that came from, perhaps related to the poignant guide:
> I suspect `0..=n` would work similarly well, but I've not seen a real language to ever do that yet
This could be extended to cover `0=..=n`, `0<..=n`, `0<..<n` and `0<..=n`.
You can actually define that syntax in Haskell:
Prelude> let a =..= b = [a..b]
Prelude> let a <..= b = [(a+1)..b]
Prelude> let a <..< b = [(a+1)..(b-1)]
Prelude> let a =..< b = [a..(b-1)]
Prelude> (1 =..= 4, 1 <..= 4, 1 <..< 4, 1 =..< 4)
([1,2,3,4],[2,3,4],[2,3],[1,2,3])
As an alternative opinion, I personally hate when ranges are exclusive by default. In addition to it feeling somewhat unintuitive to me that I need to use range(0, 6) to include 5, it also makes downward ranges quite awkward, e.g. needing range(5, -1) to count from 5 to 0.
Exclusive by default is designed to fit with 0-based indexing (0..length(v), instead 0..(length(v)-1)). That said, this thinking is less relevant in languages with iterators/ranges and doubly so ones that offer a way to explicitly, but abstractly, iterate over the indices of a vector/array.
On the point of downward ranges, you can often reverse the range explicitly, rather than swapping the endpoints, like reversed(range(0, 6)) or range(0, 6)[::-1] in Python (vs. range(5, -1, -1)). Of course, this isn't nearly as syntactically nice as range(5, 0)... but that comes with its own problems: automatically iterating backwards in ranges has been really annoying every time I've encountered it (mainly in R), requiring extra care and a pile of extra ifs and/or mins & maxs.
Right-Exclusive ranges are superior to inclusive ranges because they can represent empty ranges, which removes one rare degenerate case and not overemphasizing it.
Another benefit: creating a series of right-exclusive ranges from a sequence [a, b, c, f] is easy: [a, b) [b, c) [c, f)
In the early beta release of Swift 0.x, they used x..y for half-open ranges and x...y for closed ranges. This confused people (especially since Ruby already used the same operators but the other way around), so they changed the half-open operator to x..<y.
How is the inclusive range operator implemented in Kotlin? Something like `for (i in 0..count)` needs to iterate count + 1 times, which may overflow the size of count's type - annoying to implement.
As someone who's never programmed in Scala, it's not intuitive to me at all that "until" means exclusive, given that "to" (which is basically a synonym) means inclusive.
Is there any language where the meaning isn't immediately clear? I haven't seen a language that didn't differentiate between '<=' and '<'. The syntax of just '..' is a little unclear at first however, but it is simply a requirement of learning the language and the idioms
it's not. i've never used swift, and the meaning was instantly obvious - i'd call that a very elegant solution to a common problem i've seen in several languages.
Read it as "For 0 to count" basically. "0... (spread operator) less than 0. It seems confusing to me as well at first read but I'm used to writing for loops by hand uphill both ways.