Project

General

Profile

Actions

Feature #20818

open

Allow passing a block to Hash#store (to update current value)

Added by furunkel (Julian Aron Prenner) 27 days ago. Updated 17 days ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:119632]

Description

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:

counts = {}
elements.each do |element|
  counts.store(element){ (_1 || 0) + element.weight}
end

or even more elegant with a default value:

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

Actions

Also available in: Atom PDF

Like0
Like0