Issue #20080 has been updated by matz (Yukihiro Matsumoto).
Actually, I don't see the clear benefit of the proposal. `first, last = range.bounds`
can be `first = range.begin; last = range.end`, and `Range.new(*range.bounds)` can be
`range.dup`.
By adding `bounds` the code could become a little concise but only just.
In addition, I don't think the name `bounds` describe the behavior (returning `begin`,
`end` **and** `exclude_end?`).
Matz.
----------------------------------------
Feature #20080: Introduce #bounds method on Range
https://bugs.ruby-lang.org/issues/20080#change-106811
* Author: stuyam (Stuart Yamartino)
* Status: Open
* Priority: Normal
----------------------------------------
Followup Reference: #20027
**Update 1/11/24:** (based on many wonderful suggestions!)
1. Call the method `#bounds`.
```ruby
first, last = (1..300).bounds # => [1, 300]
first, last = (300..1).bounds # => [300, 1]
first, last = (..300).bounds # => [nil, 300]
first, last = (1..).bounds # => [1, nil]
```
2. Add `exclude_end?` support so re-hydration of Range works:
```ruby
b = (1..2).bounds #=> [1,2]
Range.new(*b) #=> 1..2
b = (1...2).bounds #=> [1,2,true]
Range.new(*b) #=> 1...2
```
I did a better job of outlining use cases in this comment below so I will let that speak
for itself:
https://bugs.ruby-lang.org/issues/20080#note-3
**Update: 2/13/24**
Browsing the ruby codebase I noticed that the `#as_json` method on Range (when you
`require 'json/add/range'`) does something similar to what the `#bounds` method we
are describing is doing:
https://github.com/ruby/ruby/blob/master/ext/json/lib/json/add/range.rb#L34
```ruby
{
JSON.create_id => self.class.name,
'a' => [ first, last, exclude_end? ]
}
```
This tells me we are on the right track. Though the difference here is that `exclude_end?`
is always included. I am thinking the `#bounds` should maybe always be including the
`exclude_end?` piece rather than only include it if it's `true`. I am inclined to
suggest always including the `exclude_end?` regardless of if it is true or false to avoid
confusion or people ever calling `#last` on the `#bounds` results thinking it is the
`#last` value where it could be the `#last` or `#exclude_end?` value depending on the type
or range. This would still satisfy all of the use cases outlined in this comment:
https://bugs.ruby-lang.org/issues/20080#note-3
**Therefore I think `#bounds` should just always return: `[ first, last, exclude_end?
]`**
**Original Proposal:**
This feature request is to implement a method called `#begin_and_end` on `Range` that
returns an array of the first and last value stored in a range:
```ruby
(1..300).begin_and_end #=> [1, 300]
first, last = (300..1).begin_and_end
first #=> 300
last #=> 1
```
I believe this would be a great addition to Ranges as they are often used to pass around a
single object used to hold endpoints, and this allows easier retrieval of those
endpoints.
This would allow easier deconstruction into start and end values using array
deconstruction as well as a simpler way to serialize to a more primitive object such as an
array for database storage.
This implementation was suggested by @mame in my initial feature suggestion regarding
range deconstruction:
https://bugs.ruby-lang.org/issues/20027
This implementation would work similar to how `#minmax` works where it returns an array of
two numbers, however the difference is that `#minmax` doesn't work with reverse ranges
as @Dan0042 pointed out in the link above:
```ruby
(1..42).minmax #=> [1, 42]
(42..1).minmax #=> [nil, nil]
```
--
https://bugs.ruby-lang.org/