Project

General

Profile

Actions

Feature #17342

closed

Hash#fetch_set

Added by MaxLap (Maxime Lapointe) over 3 years ago. Updated about 2 months ago.

Status:
Feedback
Assignee:
-
Target version:
-
[ruby-core:101071]

Description

I would like to propose adding the fetch_set method to Hash. It behaves just like fetch, but when using the default value (2nd argument or the block), it also sets the value in the Hash for the given key.

We often use the pattern cache[key] ||= calculation. This pattern however has a problem when the calculation could return false or nil, as in those case, the calculation is repeated each time.

I believe the best practice in that case is:

cache.fetch(key) { cache[key] = calculation }

With my suggestion, it would be:

cache.fetch_set(key) { calculation }

In these examples, each part is very short, so the fetch case is still clean. But as each part gets longer, the need to repeat cache[key] becomes more friction.

Here is a more realistic example:

# Also using the key argument to the block to avoid repeating the
# long symbol, adding some indirection
RequestStore.store.fetch(:monitor_value_is_delayed?) do |key|
  RequestStore.store[key] = !MonitorValue.where('date >= ?', Time.now - 5.minutes).exists?
end

RequestStore.store.fetch_set(:monitor_value_is_delayed?) do
  !MonitorValue.where('date >= ?', Time.now - 5.minutes).exists?
end

There is a precedent for such a method: Python has it, but with a quite confusing name: setdefault(key, default_value). This does not set a default for the whole dictionary as the name would make you think, it really just does what is proposed here. https://docs.python.org/3/library/stdtypes.html#dict.setdefault


Related issues 1 (1 open0 closed)

Related to Ruby master - Feature #20300: Hash: set value and get pre-existing value in one callOpenActions
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0