Bug #7300

Hash#[] の挙動が 1.9.3 と異なっている

Added by Hiroshi SHIBATA over 2 years ago. Updated over 2 years ago.

[ruby-dev:46440]
Status:Closed
Priority:Normal
Assignee:Nobuyoshi Nakada
ruby -v:ruby 2.0.0dev (2012-11-07) [x86_64-darwin12.2.0] Backport:

Description

Hashnil を実行すると 1.9.3 では {} となるものが 2.0.0 では ArgumentError となります。

なかださんに相談してみたら、2.0.0 の動きが不正なものをチェックしてて正しい挙動と
いうことを教えてもらいましたが、2.0.0 では duplicate の警告だけにして、
次のリリースで消すという方が良さそうに思います。

Associated revisions

Revision 37621
Added by Nobuyoshi Nakada over 2 years ago

hash.c: warn for wrong elements

  • hash.c (rb_hash_s_create): just warn for wrong elements now. [Bug #7300]

Revision 37621
Added by Nobuyoshi Nakada over 2 years ago

hash.c: warn for wrong elements

  • hash.c (rb_hash_s_create): just warn for wrong elements now. [Bug #7300]

History

#1 Updated by Akinori MUSHA over 2 years ago

これ、元のコードは何でしょうか。
もし文字通りnilなんて埋めてあったらコーディングミスなので、警告を出すくらいなら例外を出して直させるべきだと思います。

問題は、
Hash[enum.map {|x| x > 0 ? [x, x*x] : nil }]
のように動的にハッシュを作るときに意図的にnil(あるいは配列化できない任意の値)を使ってペアの生成をスキップする場合でしょうか。
これにしてもそんな仕様は最初から示されていないので、これを機に直してもらうのがいい気がします。「Hash[」で検索可能だし。

Hash[enum.map {|x| x > 0 ? [x, x*x] : nil }.compat] # minimum change
Hash[enum.flat_map {|x| x > 0 ? [x, x*x] : [] }] # 1.9+ only
{}.tap { |h| enum.each {|x| x > 0 and h[x] = x*x } }

#2 Updated by Akinori MUSHA over 2 years ago

なんかいろいろ微妙にミスった。

Hash[enum.map {|x| x > 0 ? [x, x*x] : nil }.compact] # minimum change
Hash[*enum.flat_map {|x| x > 0 ? [x, x*x] : [] }] # 1.9+ only
{}.tap { |h| enum.each {|x| x > 0 and h[x] = x*x } }

です。

#3 Updated by Hiroshi SHIBATA over 2 years ago

元のコードは以下の行になります。

https://github.com/apotonick/cells/blob/master/lib/cell/test_case.rb#L78

テストケースによっては Hashnil, nil, nil,... というような状態になるようです。
ライブラリ本体を直すべきであるということであれば、異論はありませんのでそのように動くつもりです。

#4 Updated by Yusuke Endoh over 2 years ago

  • Status changed from Open to Assigned
  • Assignee set to Nobuyoshi Nakada

柴田さん、またまたありがとうございます。

hsbt (Hiroshi SHIBATA) wrote:

元のコードは以下の行になります。

compact 足してよ、という感じで微妙なところですが、今回は警告に一票投じます (コードがすごく汚くなるとかでなければ) 。なかださん再検討お願いします。

余談ですが、「特に実用上困ったわけじゃないけど気がついた非互換 (RubySpec みたいな)」の報告もありがたいですが、「実コードに影響があった非互換」は心理的な優先度がだいぶ上がるので、その旨書いてもらえるととても嬉しいです。

Yusuke Endoh mame@tsg.ne.jp

#5 Updated by Hiroshi SHIBATA over 2 years ago

遠藤さん、了解です。

2.0.0 互換報告は手元の Rails アプリケーションでチェックした結果なので、ほとんどが実運用に影響のある問題です。
今後はそのことを詳しく書くことにします。

#6 Updated by Nobuyoshi Nakada over 2 years ago

  • Description updated (diff)

#7 Updated by Nobuyoshi Nakada over 2 years ago

全面的に無視するのはなんとなく気がすすまないんですが、nilだけ警告にするというのはどうでしょうか。

#8 Updated by Hiroshi SHIBATA over 2 years ago

redis-rb という ruby から redis を扱うライブラリにも同じコードがありました。

https://github.com/redis/redis-rb/blob/master/lib/redis.rb#L182

redis-rb では [nil, ["redis_version", "2.6.4"], ...] というような配列を Hash[] に渡して初期化しようとして落ちています。
配列が nil だけの時の [nil, nil, ...] に加えて [nil, ["valid", "valid"], ...] みたいな一部だけ nil というような配列の時でも警告をして通すような変更だと助かります。

#9 Updated by Nobuyoshi Nakada over 2 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r37621.
Hiroshi, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


hash.c: warn for wrong elements

  • hash.c (rb_hash_s_create): just warn for wrong elements now. [Bug #7300]

Also available in: Atom PDF