From: zverok.offline@... Date: 2019-12-27T11:44:07+00:00 Subject: [ruby-core:96515] [Ruby master Bug#16457] Invisible keys on hash when defining hash with Hash.new({}) 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: