概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: 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がオブジェクト指向プログラミングへのアプローチにおいて純潔であろうとしたことはこれまで一度もありません。