Bug #15518
closedgood old Infinite range notation behavior
Description
Ruby 2.5.3's behavior
# without step, it produces integer sequence
(1..Float::INFINITY).first(10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# with step, it produces floats instead of integers
(1..Float::INFINITY).step(1).first(10) #=> [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
Ruby 2.6.0's behavior
# endless range
(1..).first(10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# with step, all numbers are integer now
(1..).step(1).first(10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# old idiom with Float::INFINITY
(1..Float::INFINITY).first(10) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
(1..Float::INFINITY).step(1).first(10) #=> FloatDomainError (Infinity)
Which are intended change and which are not?
Updated by sawa (Tsuyoshi Sawada) almost 6 years ago
With finite ranges, the class of the elements in the return value seems to reflect the class of the step
parameter as shown below (although, I am not sure why the one with rational has 1
instead of (1/1)
. A bug, perhaps?):
(1..10).step(1).first(5) # => [1, 2, 3, 4, 5]
(1..10).step(1.0).first(5) # => [1.0, 2.0, 3.0, 4.0, 5.0]
(1..10).step(1/1r).first(5) #=> [1, (2/1), (3/1), (4/1), (5/1)]
Given that, without explicit step
, the returned numbers are integers, it should be understood that the default step for a range is the integer 1
:
(1..10).first(5) # => [1, 2, 3, 4, 5]
The above claim that the class of the number is determined by the step
parameter (and nothing else, such as the end of range) is confirmed by the fact that a range ending with Float::INFINITY
that has default step 1
returns integers (and not floats).
(1..Float::INFINITY).first(5) #=> [1, 2, 3, 4, 5]
Given the argument above, I think (1..Float::INFINITY).step(1).first(5)
should return integers as follows:
(1..Float::INFINITY).step(1).first(5) # => [1, 2, 3, 4, 5]
Thus, to me, neither Ruby 2.5.3 nor Ruby 2.6.0's behavior makes sense.
Updated by mrkn (Kenta Murata) almost 6 years ago
- Status changed from Open to Assigned
- Assignee set to mrkn (Kenta Murata)
Updated by mrkn (Kenta Murata) almost 6 years ago
At first, it isn't intentional behavior change. I should fix it, but I need to consider what is the correct behavior.
Ruby 2.5's behavior is given below:
$ RBENV_VERSION=2.5 irb --simple-prompt
>> (1 .. 10).first(5)
=> [1, 2, 3, 4, 5]
>> (1 .. 10.0).first(5)
=> [1, 2, 3, 4, 5]
>> (1.0 .. 10).first(5)
Traceback (most recent call last):
4: from /Users/mrkn/.rbenv/versions/2.5/bin/irb:11:in `<main>'
3: from (irb):3
2: from (irb):3:in `first'
1: from (irb):3:in `each'
TypeError (can't iterate from Float)
>> (1 .. 10r).first(5)
=> [1, 2, 3, 4, 5]
>> (1r .. 10).first(5)
Traceback (most recent call last):
4: from /Users/mrkn/.rbenv/versions/2.5/bin/irb:11:in `<main>'
3: from (irb):2
2: from (irb):2:in `first'
1: from (irb):2:in `each'
TypeError (can't iterate from Rational)
>> (1 .. 10).step(1).first(5)
=> [1, 2, 3, 4, 5]
>> (1 .. 10.0).step(1).first(5)
=> [1.0, 2.0, 3.0, 4.0, 5.0]
>> (1.0 .. 10).step(1).first(5)
=> [1.0, 2.0, 3.0, 4.0, 5.0]
>> (1 .. 10).step(1.0).first(5)
=> [1.0, 2.0, 3.0, 4.0, 5.0]
>> (1 .. 10r).step(1).first(5)
=> [1, 2, 3, 4, 5]
>> (1r .. 10).step(1).first(5)
=> [(1/1), (2/1), (3/1), (4/1), (5/1)]
>> (1 .. 10).step(1r).first(5)
=> [1, (2/1), (3/1), (4/1), (5/1)]
As you can see, the enumerator from Range#step is different from Range#each.
And, on Range#step, the result of the range with float components consists of Float values only while the result of the range with rational components does not.
The reason for this difference is that Range#step has the specialized implementation for the range with float components.
Updated by mrkn (Kenta Murata) almost 6 years ago
- Status changed from Assigned to Closed
Applied in changeset trunk|r66947.
enumerator.c: fix arith_seq_first for Infinity
-
enumerator.c (arith_seq_first): fix for Float::INFINITY.
-
test/ruby/test_arithmetic_sequence.rb: add tests.
-
numeric.c (ruby_float_step_size): export for internal use.
-
internal.h: add prototype declaration of ruby_float_step_size.
[ruby-core:90937][Bug #15518]
Updated by mrkn (Kenta Murata) almost 6 years ago
I fixed the case for ranges whose end is Float::INFINITY.
If you want to continue to discuss for the other cases, please create the new issue.
Updated by naruse (Yui NARUSE) almost 6 years ago
- Backport changed from 2.4: UNKNOWN, 2.5: UNKNOWN, 2.6: UNKNOWN to 2.4: DONTNEED, 2.5: DONTNEED, 2.6: REQUIRED
Updated by naruse (Yui NARUSE) almost 6 years ago
- Backport changed from 2.4: DONTNEED, 2.5: DONTNEED, 2.6: REQUIRED to 2.4: DONTNEED, 2.5: DONTNEED, 2.6: DONE
ruby_2_6 r66949 merged revision(s) 66947.