ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: duerst@it.aoyama.ac.jp
To: ruby-core@ruby-lang.org
Subject: [ruby-core:95127] [Ruby master Feature#16183] Hash#with_default
Date: Fri, 27 Sep 2019 08:35:33 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-81762.20190927083532.4fffb9d5d07afd9f@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-16183.20190926130122@ruby-lang.org

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>

      parent reply	other threads:[~2019-09-27  8:35 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <redmine.issue-16183.20190926130122@ruby-lang.org>
2019-09-26 13:01 ` [ruby-core:95104] [Ruby master Feature#16183] Hash#with_default zverok.offline
2019-09-26 15:52 ` [ruby-core:95114] " sawadatsuyoshi
2019-09-26 16:36 ` [ruby-core:95115] " shevegen
2019-09-26 19:23 ` [ruby-core:95117] " zverok.offline
2019-09-26 21:49 ` [ruby-core:95120] " eregontp
2019-09-27  6:02 ` [ruby-core:95125] " zverok.offline
2019-09-27  8:35 ` duerst [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-81762.20190927083532.4fffb9d5d07afd9f@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).