Issue #20300 has been updated by AMomchilov (Alexander Momchilov).
@matheusrich I like that name in general, but it's really similar to the existing
[`Hash#store`](https://ruby-doc.org/3.3.0/Hash.html#method-i-store) and the distinction is
non-obvious.
Swift calls this
[`updateValue(_:forKey:)`](https://developer.apple.com/documentation/swift/dictionary/updatevalue(_:forkey:)),
which returns a `Value?` ("the value that was replaced, or `nil` if a new key-value
pair was added."), but it has a similar problem.
I think `#exchange_value` is the best recommendation yet, because it makes it reasonably
easy to guess what the return value would be, even without reading the docs.
----------------------------------------
Feature #20300: Hash: set value and get pre-existing value in one call
https://bugs.ruby-lang.org/issues/20300#change-107022
* Author: AMomchilov (Alexander Momchilov)
* Status: Open
----------------------------------------
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
# Exact method name TBD.
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.
I'm opening to alternative name suggestions. @nobu came up with `exchange_value`,
which I think is great.
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)
```
--
https://bugs.ruby-lang.org/