From: "mame (Yusuke Endoh) via ruby-core" Date: 2024-11-07T10:25:29+00:00 Subject: [ruby-core:119799] [Ruby master Feature#20818] Allow passing a block to Hash#store (to update current value) Issue #20818 has been updated by mame (Yusuke Endoh). Discussed at the dev meeting. @matz said "I don't like the style so much, but if the patch is safe and actually improves performance, I'm willing to consider it. I'd like you to show the benchmark." I am not sure if it is safe to execute arbitrary Ruby code in the RHASH_UPDATE_ITER callback. For example, what will happen if we update the hash itself inside the block of Hash#store, like `h.store(:key){ h[:another_key] = 1 }`? Does the patch prohibit this? If it is allowed, we need to care the possibility that rehash may occur. ---------------------------------------- Feature #20818: Allow passing a block to Hash#store (to update current value) https://bugs.ruby-lang.org/issues/20818#change-110484 * Author: furunkel (Julian Aron Prenner) * Status: Open ---------------------------------------- I would like to propose a block form for `Hash#store`. In addition to passing a value, it should also be allowed to pass a block. If passed a block instead of a value, the block is called with the current value or, if unset, the hash's default value; the block's return value will be the value that is stored. This is similar to e.g., `computeIfPresent`/`computeIfAbsent` in Java (I think). I can think of several situations where this would be useful, in particular for caches and counters. For instance: ```ruby counts = {} elements.each do |element| counts.store(element){ (_1 || 0) + element.weight} end ``` or even more elegant with a default value: ```ruby counts = {} counts.default = 0 elements.each do |element| counts.store(element){ _1 + element.weight} end ``` Moreover, using the block form we should be able to do operations such as `h[k] ||= x`, `h[k] -= x`, `h[k] += x`, or more generally `h[k] = f(h[k])`, with a single "hashing round-trip". If I'm not mistaken, currently these involve two separate calls to `#[]` and `#[]=` (with two calls to `#hash`?). Finally, this makes `#store` a proper dual of `#fetch` which, similarly, can be passed a block. I have an experimental implementation of this (GitHub PR) at: https://github.com/ruby/ruby/pull/11956 -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/