Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.Sign up
Add begin-less and end-less ranges #7179
This PR introduces begin-less and end-less ranges. If most of us think this is a nice and useful feature we could merge it.
An end-less range is just a range with
A begin-less range is just a range with
These ranges have two semantics:
As a range
A range has methods like
(3..).each do |x| puts x break if some_condition end
You can't invoke
(..3).reverse_each do |x| # ... eventually yields 0, -1, -2 end
Note that a begin-less range isn't equivalent to a range that starts with
A range also has a
number = rand(1..10) case number when ..3 then "foo" when (3..5) then "bar" when (6..) then "bar" # or just else end
(well, maybe the above isn't a good example because there's still an else
numbers = [1, 10, 3, 4, 5, 8] numbers.select(6..) # => [10, 8] numbers.select(..6) # => [1, 3, 4, 5]
The above is the same as:
I think the former is a bit more readable.
num = some_number num = 10 if num <= 10
We can do:
num = num.clamp(10..)
Same goes with capping to a max.
In Ruby 2.6 there was also an example like this:
[1, 2, 3].zip(6..) # => [[1, 6], [2, 7], [3, 8]]
which is nice (no need to explicitly specify an upper bound) but currently doesn't work in Crystal (but I might make it work soon).
As an indexer
As an indexer, an endless range means "until the end of the collection". It's equivalent to passing
ary = [1, 2, 3, 4, 5] ary[2..] # => [3, 4, 5] ary[2...] # => [3, 4, 5]
This works for any indexable (
For a begin-less range it's equivalent to passing
ary = [1, 2, 3, 4, 5] ary[..2] # => [1, 2, 3]
The catch-all range
Because the begin and end are now optional, we can also write
# replace all elements of an array with a single element ary = [1, 2, 3, 4, 5] ary[..] = 3 ary # =>  # replace all elements of an array ary = [1, 2, 3, 4, 5] ary[..] = [6, 7, 8] ary # => [6, 7, 8] # fill an array with a value ary = [1, 2, 3] ary.fill(8, ..) ary # => [8, 8, 8] # another way to dup an array ary = [1, 2, 3] b = ary[..]
case number when .. then "duh" end
Yeah... not a lot of uses, but the semantics are consistent.
Ideally I would change the
Changing the parser was relatively simple.
2 times, most recently
Dec 11, 2018
referenced this pull request
Dec 11, 2018
Your reasoning is correct. However an endless range means "up to infinite" or without an end. In the case of indexing a collection, because the size is finite, it just means to take everything available. There the exclusive/inclusive distinction doesn't make sense.
Maybe to prevent this small confusion we could make an endless exclusive range a syntax error. Thoughts?
@RX14 All comments addressed (except one I didn't understand).
Given that this PR also adds specs for
The following thought is for ranges in general:
This way you would easily disambiguate the 2: when there is no space it would ALWAYS be a range, when there is spaces it can only be a partial range (begin and/or end -less range)
This can probably wait a bit, I'll open a discussion about this when this PR is merged
No problem on my side with the