Project

General

Profile

Actions

Feature #17342

open

Hash#fetch_set

Added by MaxLap (Maxime Lapointe) 5 months ago. Updated 5 months ago.

Status:
Feedback
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:101232]

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

Actions

Also available in: Atom PDF