Project

General

Profile

Feature #15573

Permit zero step in Numeric#step and Range#step

Added by mrkn (Kenta Murata) over 1 year ago. Updated about 1 month ago.

Status:
Open
Priority:
Normal
Target version:
-
[ruby-core:91324]

Description

Numeric#step disallows zero in the 2nd argument, but it allows zero passed as the value of by: keyword argument. I confirmed that this inconsistency exists since 2.3. I want to allow zero in the 2nd argument, too.

>> 1.step(10, by: 0) { break }
=> nil
>> 1.step(10, 0) { break }
Traceback (most recent call last):
        5: from /Users/mrkn/.rbenv/versions/2.6.0/bin/irb:23:in `<main>'
        4: from /Users/mrkn/.rbenv/versions/2.6.0/bin/irb:23:in `load'
        3: from /Users/mrkn/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2: from (irb):5
        1: from (irb):5:in `step'
ArgumentError (step can't be 0)

Moreover, Range#step disallows zero if a block is given. I want to relax also this restriction.

>> (1..10).step(0) { break }
Traceback (most recent call last):
        6: from /Users/mrkn/.rbenv/versions/2.6.0/bin/irb:23:in `<main>'
        5: from /Users/mrkn/.rbenv/versions/2.6.0/bin/irb:23:in `load'
        4: from /Users/mrkn/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        3: from (irb):6
        2: from (irb):6:in `rescue in irb_binding'
        1: from (irb):6:in `step'
ArgumentError (step can't be 0)
#1

Updated by mrkn (Kenta Murata) over 1 year ago

  • Description updated (diff)

Updated by shyouhei (Shyouhei Urabe) over 1 year ago

mrkn (Kenta Murata) wrote:

I want to relax also this restriction.

Tell us why? Consistency?

Updated by sawa (Tsuyoshi Sawada) over 1 year ago

There is also inconsistency in that, without the block, 0 is allowed in these forms.

1.step(10, 0) # => ok
1.step(10, 0){} # => ArgumentError: step can't be 0
(1..10).step(0) # => ok
(1..10).step(0){} # => ArgumentError: step can't be 0

Since 0 can already sneak in, disallowing it just when the block is given makes it confusing. I agree that it should be relaxed.

Oops, sorry for the post if this was what mfkn has already pointed out.

Updated by shevegen (Robert A. Heiler) over 1 year ago

I can't say in which way to change it but I think this is indeed surprising
behaviour and should be changed either way towards more consistency
if possible.

Updated by mrkn (Kenta Murata) over 1 year ago

Tell us why? Consistency?

The reason is that zero step allows when the block is not given.

>> 1.step(10, 0).each { break }
=> nil
irb(main):005:0> (1..10).step(0)
=> ((1..10).step(0))
>> (1..10).step(0).each { break }
=> nil

Updated by matz (Yukihiro Matsumoto) over 1 year ago

For this case, consistency matters. I thought it is better to raise an error on zero step. But mrkn (Kenta Murata) can choose whatever behavior he believes right.

Matz.

#7

Updated by mrkn (Kenta Murata) over 1 year ago

  • Assignee changed from matz (Yukihiro Matsumoto) to mrkn (Kenta Murata)

Updated by fatkodima (Dima Fatko) about 1 month ago

Mathematically, it is allowed that step can be 0, but from practical stand point - this is an infinite loop waiting to be happen.

The original issue was about inconsistencies, so I decided to allow 0 for consistency (mainly because there is an ArithmeticSequence which allows that) and deprecate raising an exception. Or we can rewrite the ArithmeticSequence to raise and deprecate accepting 0 for all methods.

PR: https://github.com/ruby/ruby/pull/3462

Updated by Dan0042 (Daniel DeLorme) about 1 month ago

What is the purpose of a zero step? I cannot understand why/how it would be used.

Updated by fatkodima (Dima Fatko) about 1 month ago

Dan0042 (Daniel DeLorme) wrote in #note-9:

What is the purpose of a zero step? I cannot understand why/how it would be used.

This is basically an infinite generator of the same number. I haven't real usecases for this also.

Updated by zverok (Victor Shepelev) about 1 month ago

What is the purpose of a zero step? I cannot understand why/how it would be used.

This is basically an infinite generator of the same number. I haven't real usecases for this also.

For edge cases like this, they typically emerge on dynamic calculation (and if the calculation is mathematically sound, they probably shouldn't raise). Like, I dunno, something like (intentionally vague)

(lower_threshold..upper_threshold).step(avg_object_size).take(5)

...will in edge case produce 5 copies of lower_threshold, which, depending on application logic, might be a useful result. So, ArgumentError("Nobody on the tracker have seen a sense in this") is probably undesireable.

Updated by fatkodima (Dima Fatko) about 1 month ago

zverok (Victor Shepelev)

Without take (or simply if step will have a block) this will be problematic.
But, agreed, good example.

Also available in: Atom PDF