From: chris@... Date: 2020-11-25T22:16:40+00:00 Subject: [ruby-core:101074] [Ruby master Feature#17342] Hash#fetch_set Issue #17342 has been updated by chrisseaton (Chris Seaton). `#fetch_or_set` could be a good name. > Why do we need a block for the second parameter? Can't that just be an ordinary parameter? Because we don't want to do the work of calculating the initial value if it isn't needed because the value is already set. ---------------------------------------- Feature #17342: Hash#fetch_set https://bugs.ruby-lang.org/issues/17342#change-88748 * Author: MaxLap (Maxime Lapointe) * Status: Open * Priority: Normal ---------------------------------------- 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: ```ruby cache.fetch(key) { cache[key] = calculation } ``` With my suggestion, it would be: ```ruby 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: ```ruby # 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 -- https://bugs.ruby-lang.org/ Unsubscribe: