Issue #16457 has been updated by zverok (Victor Shepelev).


The logic of this behavior is:
1. `my_hash[:my_key]` returns `my_hash.default` (not assigning it to any key)
2. `my_hash[:my_key].merge!(value: '')` updates this object
3. Now this object is available for ANY key in its updated form, not only `:my_key`:

```ruby
my_hash = Hash.new({})
my_hash.default # => {} 

my_hash[:my_key] #=> {}
my_hash[:my_key].merge!(value: '')

my_hash.default # => {:value=>""}

# Nothing special about my_key here, you just have your default:
my_hash.dig(:my_key) #=> {:value=>""}
my_hash[:my_key] #=> {:value=>""}

# It would be the same with any key:
my_hash[:any_other_key] #=> {:value=>""}
```
...even if a bit surprising on a first occurence, nothing is "hidden" here ;)

This types of subtle errors can be avoided by:
```ruby
# 1. Either passing blocks instead of single value:
my_hash = Hash.new { {} }
my_hash[:my_key].merge!(value: '')
my_hash[:my_key] #=> {}

# 2. Passing unchangeable values as defaults:
my_hash = Hash.new({}.freeze)
my_hash[:my_key].merge!(value: '') # FrozenError (can't modify frozen Hash: {})
```


----------------------------------------
Bug #16457: Invisible keys on hash when defining hash with Hash.new({})
https://bugs.ruby-lang.org/issues/16457#change-83447

* Author: Farhad (Farhad Eyvazli)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 2.6.3
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN
----------------------------------------
When using ``` Hash.new()``` to initialize a hash, we all know for undefined it will return specific value which sent as a parameter to the ```Hash.new``
But when doing something like that keys get invisible

```ruby
my_hash: Hash.new({})

my_hasy[:my_key] #=> {}
my_hash[:my_key].merge!(value: '')

my_hash.keys #=> []
my_hash.fetch(:my_key) #=> KeyError: key not found: :my_key

my_hash.dig(:my_key) #=> {:value=>""}
my_hash[:my_key] #=> {:value=>""}
```

Maybe it's normal behavior because, for each missing key, it initialize new empty has and merge it to that. But I'm not sure it can cause a memory leak or not when removing the main hash (:my_hash)
 



-- 
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>