📌
[Bug #20307] compare_by_identity と Hash#update のバグ報告
[Bug #20307] Hash#update
from compare_by_identity hash can have unfrozen string keys
- 以下のように
compare_by_identity
な Hash をHash#update
で取り込むと意図しない挙動になるというバグ報告- どうやってみつけるのこれ…
key = "a"
hash1 = {}.compare_by_identity
hash1[key] = 0
hash2 = {}.update(hash1)
pp hash1 # => {"a"=>0}
pp hash2 # => {"a"=>0}
pp hash1.compare_by_identity? # => true
pp hash2.compare_by_identity? # => false
key.upcase!
# key は大文字の "A" として扱われているが
pp hash2 # => {"A"=>0}
pp hash2.keys # => ["A"]
# 添字アクセスなどはできない状態になっている
pp hash2[key] # => nil
pp ((hash2.fetch(key) rescue $!))
# => #<KeyError: key not found: "A">
# compare_by_identity と同じような挙動になる
hash2["A"] = 1
pp hash2
# => {"A"=>0, "A"=>1}
- この問題は開発版の Ruby 3.4 で修正済み
- ちなみに
Hash#compare_by_identity
はレシーバの Hash のキーの一致判定を『オブジェクトの同一性で判定する』ように変更するメソッド
hash = { "a" => "homu" }
# これは `"a" のキーが同じオブジェクトとして判定されるので上書きされる
hash["a"] = "mami"
pp hash # => {"a"=>"mami"}
hash.compare_by_identity
# compare_by_identity すると object_id で比較されるようになるので上書きされない
hash["a"] = "mado"
pp hash # => {"a"=>"mami", "a"=>"mado"}
Discussion