Project

General

Profile

Actions

Feature #15573

closed

Permit zero step in Numeric#step and Range#step

Added by mrkn (Kenta Murata) over 2 years ago. Updated 9 months ago.

Status:
Closed
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)
Actions #1

Updated by mrkn (Kenta Murata) over 2 years ago

  • Description updated (diff)

Updated by shyouhei (Shyouhei Urabe) over 2 years ago

mrkn (Kenta Murata) wrote:

I want to relax also this restriction.

Tell us why? Consistency?

Updated by sawa (Tsuyoshi Sawada) over 2 years 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 2 years 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 2 years 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 2 years 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.

Actions #7

Updated by mrkn (Kenta Murata) over 2 years ago

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

Updated by fatkodima (Dima Fatko) 11 months 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) 11 months ago

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

Updated by fatkodima (Dima Fatko) 11 months 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) 11 months 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) 11 months ago

zverok (Victor Shepelev)

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

Actions #13

Updated by Anonymous 9 months ago

  • Status changed from Open to Closed

Applied in changeset git|f754b422855131111092c0c147d744775cc4793f.


numeric.c, range.c: prohibit zero step

  • numeric.c: prohibit zero step in Numeric#step

  • range.c: prohibit zero step in Range#step

  • Fix ruby-spec

[Feature #15573]

Actions

Also available in: Atom PDF