Bug #16187

Hash#replace no longer rehashes keys for small (array table) hashes

Added by dylants (Dylan Thacker-Smith) over 1 year ago. Updated over 1 year ago.

Target version:
ruby -v:
ruby 2.7.0dev (2019-09-27T02:24:58Z master 660c7e050f) [x86_64-darwin18]


Here is a script that shows the problem

mutable_key = [1]
h = { mutable_key => 'a' }
mutable_key[0] = 2
p(h == {}.replace(h))

which outputs true in ruby 2.5 and lower versions and false in ruby 2.6 and later versions.

This is because ruby 2.6 introduced array table backed hashes and rb_hash_replace uses ar_copy(hash, hash2) when both hashes use an array table. If either hash used a symbol table, then the it would rehash the keys. This can be shown by forcing an symbol table to be used using Hash#compare_by_identity

mutable_key = [1]
h = { mutable_key => 'a' }
mutable_key[0] = 2
p(h == {}.replace(h))

which returns true in all versions of ruby.

I think Hash#replace should definitely be consistent about whether it rehashes or not.

In ko1 (Koichi Sasada) suggested using rb_hash_replace to implement Hash#initialize_copy. Since Hash#dup already has tests to ensure that it rehashes, I think it makes sense to have Hash#replace go back to always rehashing so we can share an implementation between these methods. I've opened which does this and addresses

Updated by dylants (Dylan Thacker-Smith) over 1 year ago

This can be closed now. It was fixed by commit b9702590445dfea62d271d0a5c942b7adfaaacdd.

Sorry, I should have linked to this bug in the relevant commit in that changeset.


Updated by jeremyevans0 (Jeremy Evans) over 1 year ago

  • Status changed from Open to Closed

Also available in: Atom PDF