From: duerst@... Date: 2019-09-27T08:35:33+00:00 Subject: [ruby-core:95127] [Ruby master Feature#16183] Hash#with_default Issue #16183 has been updated by duerst (Martin D�rst). zverok (Victor Shepelev) wrote: > Eregon (Benoit Daloze) wrote: > > That means a copy of the Hash is necessary on each call to `#with_default`. > > Yes, the same way it is for, say, `merge`, and we still use it in a lot of cases even when source hash would be dropped -- for the sake of chainability: Well, yes, but at least in my view, `merge` is a two-sided (symmetric) operation. There are two hashes, and you merge them. It would be strange if one of them is changed, but not the other. The fact that Ruby, because it's object-oriented, uses one of the hashes as a receiver is in first approximation just a syntax issue. Of course there are cases where `merge` is used in a asymmetric way (your examples are all of this nature), but that's not the original nature of `merge`. `with_default`, on the other hand, similar to the current methods that set a default, is *by nature* asymmetric. Also, it's really rare (if such examples exist at all) that a new hash is needed because there's both a version with a default and a version without a default. So adding the default in place and not making a copy seems to be the natural thing to do. I think that when you go through Ruby's builtin classes and standard library, there are many case that can easily explained in similar terms. ---------------------------------------- Feature #16183: Hash#with_default https://bugs.ruby-lang.org/issues/16183#change-81762 * Author: zverok (Victor Shepelev) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- Reasons: there is no way, currently, to *declaratively* define Hash with default value (for example, to store it in constant, or use in an expression). Which leads to code more or less like this: ```ruby FONTS = { title: 'Arial', body: 'Times New Roman', blockquote: 'Tahoma' }.tap { |h| h.default = 'Courier' }.freeze # Grouping indexes: ary.each_with_object(Hash.new { |h, k| h[k] = [] }).with_index { |(el, h), idx| h[el.downcase] << idx } ``` With proposed method: ```ruby FONTS = { title: 'Arial', body: 'Times New Roman', blockquote: 'Tahoma' }.with_default('Courier').freeze ary.each_with_object({}.with_default { [] }).with_index { |(el, h), idx| h[el.downcase] << idx } ``` About the block synopsys: I am not 100% sure, but I believe that _most_ of the time when `default_proc` provided, it looks like `{ |h, k| h[k] = some_calculation }`. So, I believe for this "declarative simplification" of defaults, it is acceptable to assume it as the only behavior (pass only key to block, and always store block's result); more flexible form would still be accessible with `Hash.new`. -- 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>