Feature #20300
Updated by AMomchilov (Alexander Momchilov) 9 months ago
When using a Hash, sometimes you want to set a new value, *and* see what was already there. Today, you **have** to do this in two steps:
```ruby
h = { k: "old value" }
# 1. Do a look-up for `:k`.
old_value = h[:k]
# 2. Do another look-up for `:k`, even though we just did that!
h[:k] = "new value"
use(old_value)
```
This requires two separate `Hash` look-ups for `:k`. This is fine for symbols, but is expensive if computing `#hash` or `#eql?` is expensive for the key. It's impossible to work around this today from pure Ruby code.
One example use case is `Set#add?`. See https://bugs.ruby-lang.org/issues/20301 for more details.
I propose adding `Hash#update_value`, which has semantics are similar to this Ruby snippet:
```ruby
class Hash
def update_value(key, new_value)
old_value = self[key]
self[key] = new_value
old_value
end
end
```
... except it'll be implemented in C, with modifications to `tbl_update` that achieves this with a hash-lookup.
Here's a PR with a PoC implementation: https://github.com/ruby/ruby/pull/10092
```ruby
h = { k: "old value" }
# Does only a single hash look-up
old_value = h.update_value(:k, "new value")
use(old_value)