Bug #19231
openInteger#step and Float::INFINITY - inconsistent behaviour when called with and without a block
Description
The initial issue was reported here https://github.com/oracle/truffleruby/issues/2797.
0.step(Float::INFINITY, 10)
returns:
-
Integers
when called with a block -
Floats
when called without a block
I would expect Floats
to be returned in both cases.
Examples:
0.step(Float::INFINITY, 10).take(1).map(&:class)
=> [Float]
0.step(Float::INFINITY, 10) { |offset| p offset.class; break }
# Integer
When to
argument is a finite Float
value then calling with a block returns Floats
as well:
0.step(100.0, 10) { |offset| p offset.class; break }
# Float
Wondering whether it's intentional behaviour.
I've found a related issue https://bugs.ruby-lang.org/issues/15518.
Updated by andrykonchin (Andrew Konchin) 6 months ago
- Description updated (diff)
Updated by mrkn (Kenta Murata) 6 months ago
0.step(Float::INFINITY, 10).each
generates Float values until Ruby 2.0 and after Ruby 2.6, but it generates Integer values between Ruby 2.1 and 2.5. The reason why the behavior changes after Ruby 2.6 is due to ArithmeticSequence.
0.step(Float::INFINITY, 10) { ... }
generates Float values until Ruby 2.0, but it generates Integer values after Ruby 2.1.
Hence it's also possible that the right behavior is to generate Integer values rather than Float. We need to know the reason for the behavior change in Ruby 2.1.
Updated by Eregon (Benoit Daloze) 6 months ago
IMHO Integer makes sense so one can step by N from 0 to infinity with 0.step(Float::INFINITY, 10)
(with Numeric#step
), since there is no Integer::INFINITY
.
Using Float also can cause significant errors with a big enough step or values.
So the rule would be "use floats if receiver
or step
is Float (ignore to/limit
's type), otherwise leave them as-is.
The keyword form already uses integers for "step infinitely":
> 0.step(by: 10).take 2
=> [0, 10]
> 0.step(by: 10) { break _1 }
=> 0
Probably we need to be consistent with Range#step
too:
> (0..).step(10) { break _1 }
=> 0
> (0..).step(10).take 2
=> [0, 10]
> (0..Float::INFINITY).step(10) { break _1 }
=> 0.0
> (0..Float::INFINITY).step(10).take 2
=> [0.0, 10.0]