From: dylan.smith@... Date: 2019-09-27T22:35:18+00:00 Subject: [ruby-core:95136] [Ruby master Bug#16187] Hash#replace no longer rehashes keys for small (array table) hashes Issue #16187 has been reported by dylants (Dylan Thacker-Smith). ---------------------------------------- Bug #16187: Hash#replace no longer rehashes keys for small (array table) hashes https://bugs.ruby-lang.org/issues/16187 * Author: dylants (Dylan Thacker-Smith) * Status: Open * Priority: Normal * Assignee: * Target version: * ruby -v: ruby 2.7.0dev (2019-09-27T02:24:58Z master 660c7e050f) [x86_64-darwin18] * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN ---------------------------------------- Here is a script that shows the problem ```ruby 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' } h.compare_by_identity 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 https://bugs.ruby-lang.org/issues/16121 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 https://github.com/ruby/ruby/pull/2489 which does this and addresses https://bugs.ruby-lang.org/issues/16121 -- https://bugs.ruby-lang.org/ Unsubscribe: