概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Watch Out For nil in Ranges - Andy Croll
- 原文公開日: 2019/05/19
- 著者: Andy Croll
Ruby: Rangeにnilが入ってないか注意しよう(翻訳)
Ruby 2.6ではRangeの構文が拡張され、終端に無限の値も使えるようになったことで「エンドレス」を扱えるようになりました。この新しい構文はRubyドキュメント(英語)に記載されています。
この構文は、「ある日付から任意の未来の日付までの期間」などの概念を表現するのに優れていますが、構文に新しいシンタックスシュガーをまぶして変更したことで、既存の振る舞いが変わります。
以前のRubyの場合
rangeにnilを渡すとArgumentErrorになる。
end_of_range = nil
(1..end_of_range).map { |i| do_something(i) }
#=> ArgumentError (bad value for range)
現在のRubyの場合
Rangeの終端のnilはエラーではなくなり、「エンドレス」のrangeを表す。
end_of_range = nil
(1..end_of_range).map { |i| do_something(i) }
#=> infinite loop!
注意が必要な理由
エンドレスのrangeを作成する機能はRuby 2.5以前にもありましたが、Float::INFINITYなどのように明示的な特殊定数を用いる方法だけが利用可能でした。
メソッドの結果が予期せずnilになってしまう可能性の高い言語で、nilがrangeの有効な入力であるとみなされるようになると、見つけにくい誤りの発生場所が確実にまた1つ増えてしまいます。
避けて通れない理由
この構文は言語に組み込まれているので、実際には選択の余地がありません。
しかし、Rangeに渡される値のチェックを励行することで身を守ることは可能です。コードのあちこちにnilチェックをばらまくのは「グッドプラクティス」とみなされていませんが、Rubyがオブジェクト指向プログラミングへのアプローチにおいて純潔であろうとしたことはこれまで一度もありません。