Issue #16187 has been updated by dylants (Dylan Thacker-Smith).


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

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

----------------------------------------
Bug #16187: Hash#replace no longer rehashes keys for small (array table) hashes
https://bugs.ruby-lang.org/issues/16187#change-82208

* 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: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>