Hacker News new | past | comments | ask | show | jobs | submit login

0..<count is a lovely little piece of language design



An alternative approach is Guava's Range class:

Range.closed(1,5) == [1,5]

Range.open(1,5) == (1,5)

Range.openClosed(1,5) == (1,5]

Range.closedOpen(1,5) == [1,5)

Range.greaterThan(1) == (1,infinity)

Range.atLeast(1) == [1,infinity)

That class always strikes me as having high power-to-weight. It has methods like encloses(anotherRange), contains(aValue), and others.

https://google.github.io/guava/releases/19.0/api/docs/com/go...


Should the second "closed" be "closed Open" (with the corresponding change to the rest of the line)?


Fixed, thanks.


What does a Guava two-Integer-element array literal look like?


Sorry, I didn't explain myself well.

Range.closed(1,5) is the syntax used to refer to what a mathematician would call [1,5].

Guava is just a Java library. In Java 9, a two-Integer-element list literal will be List.of(9000, 9001).


Too verbose for me. I always prefer short syntactic sugar.


What do you like about it? I was actually thinking the opposite...

EDIT: Genuinely curious, this is not meant to troll or start a war.

I like the more explicit feeling `count-1`. I'd use either...


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.


Why is it a..b instead of the logical a..=b or a..<=b?


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.


"a..b - 1" can also be written as "a until b" in Kotlin.


Which is not as obvious. I much prefer a..<b.


When I see "0..n" I wonder whether the range is inclusive or exclusive of n.

When I see "0..<n" I know the range is exclusive of n.


Yes, but the corresponding design decision would be "0..=n". Swift's "0...n" is a bit less obvious.

Also, exclusivity is almost always what you want, so "0..n" should just default to exclusivity and "0...n" could be inclusive.


This is the exact opposite to ruby, which uses `0..n` as inclusive, and `0...n` as exclusive

http://stackoverflow.com/questions/9690801/difference-betwee...

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:

http://poignant.guide/book/chapter-3.html#section2

I actually find in practice the swift ranges are the only ones I can reliably use without having to stop and look up the reference syntax every time.

For some reason, for me, `0..<n` reads as "0 through less than n" which signals to my brain a clear signal of an exclusive range.

Then I can work from there and if it doesn't have the < symbol it must be exclusive.

I suspect `0..=n` would work similarly well, but I've not seen a real language to ever do that yet


> 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.


I understand the benefits, I just personally don't prefer it. But this is just my subjective opinion.


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)


On the other hand, it's easier to determine the number of items in a range if it is exclusive; range(n, m) contains abs(m - n) items.

Also, inclusive doesn't allow you to specify empty ranges. That may mean having to add if statements to your code, making it uglier.

I would prefer using notations [m,n) and [m,n], even though that uses a notation used in mathematics for a set to specify a sequence.

Of course, one would want (m,n) and (m,n], too, then, but that first one probably would make parsing your language difficult.


It's due to the zero-based indexing, right? In something like lua, that starts at 1, inclusive makes more sense.


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.


It confused me as well. "0.. is less than count"?


Personally, I find that just having "0..count" requires a bit of thinking on my part trying to decide if it's inclusive or not.

"0..<count" instantly tells me that it's not including value, and follows the matematical interval notification [0..count] vs [0..count)


I'd prefer 0..count or 0..(count - 1) then.


I believe it was discussed in Swift Evolution, not confusing.

    0...1 //0 to 1
Note: triple dot.

    0..2 //error: repl.swift:1:2: error: use of unresolved operator '..'


    0..<1 //0 to <1


".." has a meaning – why are you leaving it out of the translation?


I'd usually use ".." in the context of e.g. "2..3" to express a range but "<" to express a condition so I don't find it natural.


Add spaces for clarity:

  0 ..< count
I think Swift programmers should adopt this style.


0 ... count-1 fails when count is equal to the smallest value the type can represent (for example, if it's 0 and unsigned).


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.


>needs to iterate count + 1 times, which may overflow the size of count's type - annoying to implement

How's that different from:

  for (int i=0; i<=count; i++)
in e.g. C99?


I don't see where the overflow would come into play since count is the terminal value and count is necessarily representable in its type.


In Kotlin it's much more common to write the following, which is exclusive:

   count.forEach {
      // do things
   }


Indeed a clear syntax.

OTOH, a "loop .. for .. {upto, below} count" leaves less questions in a casual code review :)


I prefer explicit words over symbols, like in Scala:

scala> 1 to 3

scala.collection.immutable.Range.Inclusive = Range(1, 2, 3)

scala> 1 until 3

scala.collection.immutable.Range = Range(1, 2)


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.


How would you feel about

  > 1 through 3
  # [1, 2, 3]

  > 1 until 3 # or 1 to 3
  # [1, 2]
as explicit word range notation?


Agreed, Scala's approach to ranges is one of the best out there from my experience.


I can't tell whether this is sarcasm or not. What does the '<' mean in this case? I'm assuming an exclusive upper bound.


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.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: