Bug #14845
closedEndless Range with nil
Description
endless Rangeで次のケースで困ることがあります。
- 1..nilはendless Rangeになる
- endless Rangeはto_aすると返ってこなくなる
- 1..変数 のケースで意図せずendless Rangeになる可能性があり、そのときto_aすると返ってこなくなる
Ruby 2.5.1 では 1..nil はArgumentError (bad value for range) になります。
たとえば、 1..nil がendless Rangeではなくエラーになればこの問題は解決します。
Info¶
- An endless range
(1..)
: https://bugs.ruby-lang.org/issues/12912 - twitter での話 : https://twitter.com/igaiga555/status/1006715631796813824
Files
Updated by mame (Yusuke Endoh) over 6 years ago
現状の挙動はそれはそれで便利そう※なので、early failure と便利さとのトレードオフです。どっちがいいでしょうね。
※たとえば SQL の DSL で count: (min..max)
という Range を書いたとき、max = nil
にするだけで「上限なし」を表現できるという使い方が考えられます。(1..nil)
がエラーになると、count: max ? (min..max) : (min..)
とかいう記述が必要になり、DSL としては終了です。
問題を to_a
に限れば、(1..nil).to_a
や enum.cycle.to_a
のように、明らかに停止しない to_a
呼び出しを例外にするという解決もありえると思います(「明らかに停止しない」が本当に正しいかどうか自信が持てないところですが)。
うっかり (1..nil)
を作ってしまったというリアルな例などがあると、議論が捗りそうです。
Updated by mame (Yusuke Endoh) over 6 years ago
- Status changed from Open to Closed
Applied in changeset trunk|r63646.
range.c: prohibit (1..nil)
Now endless range can be created by either a literal (1..)
or explicit
range creation Range.new(1, nil)
. [Bug #14845]
This change is intended for "early failure"; for example,
(1..var).to_a
causes out of memory if var
is inadvertently nil.
Updated by mame (Yusuke Endoh) over 6 years ago
- Status changed from Closed to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
https://twitter.com/yukihiro_matz/status/1006737384820445184
いやあ、エラーではねた方がいいんじゃないですかね。
ていうのがあったので、とりあえず r63646 で (1..nil)
を禁止しました。ただし Range.new(1, nil)
は許しています(そうしないと Range のサブクラスを endless にする手段がないので)。
個人的には、DSL が終了してしまったのと、無駄に複雑になった気がして、あんまり好きじゃないです。次の開発者会議で相談させてください。
Updated by mame (Yusuke Endoh) over 6 years ago
- Status changed from Assigned to Closed
Applied in changeset commit:ruby-git|48de2ea5f9b9067779acb0f7f76e5f879f2b42c0.
range.c: prohibit (1..nil)
Now endless range can be created by either a literal (1..)
or explicit
range creation Range.new(1, nil)
. [Bug #14845]
This change is intended for "early failure"; for example,
(1..var).to_a
causes out of memory if var
is inadvertently nil.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63646 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Updated by matz (Yukihiro Matsumoto) over 6 years ago
I meant (1..).to_a
to raise an exception (for apparent infinity loop), not prohibiting 1..nil
'.
Matz.
Updated by mame (Yusuke Endoh) over 6 years ago
- Status changed from Closed to Assigned
matz (Yukihiro Matsumoto) wrote:
I meant
(1..).to_a
to raise an exception (for apparent infinity loop), not prohibiting1..nil
'.Matz.
Sorry for my misunderstanding. I reverted r63646.
Updated by mame (Yusuke Endoh) over 6 years ago
- File range_to_a.patch range_to_a.patch added
I'm attaching a patch for Range#to_a
that raises an RangeError for an endless range, and that calls super to Enumerable#to_a
for a normal range.
Updated by znz (Kazuhiro NISHIYAMA) over 6 years ago
別チケットにした方が良いのかもしれませんが、関連するのでここにコメントしておきます。
Range.new(1)
のように終端を省略できるようにするのはどうでしょうか?
endless range の時は exclude_end を指定できても違いがないようなので、現状では問題がなさそうに思います。
beginless などの可能性を考えるとキーワード引数も受け付けるようにして、 Range.new(begin: 1, endless: true)
や Range.new(begin: 1, end: 9, exclude_end: true)
のようにかけると良いかもしれません。
Updated by mame (Yusuke Endoh) over 6 years ago
- Status changed from Assigned to Closed
Applied in changeset trunk|r63714.
range.c: Range#to_a now raises RangeError if it is endless
Fixes [Bug #14845]
Updated by mame (Yusuke Endoh) almost 4 years ago
- Related to Misc #17637: Endless ranges with `nil` boundary weird behavior added