Issue #20300 has been updated by nobu (Nobuyoshi Nakada).
I want `ENV.exchange_value` rather than `Hash#exchange_value`.
----------------------------------------
Feature #20300: Hash: set value and get pre-existing value in one call
https://bugs.ruby-lang.org/issues/20300#change-107215
* 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#exchange_value`, which has semantics are similar to this Ruby
snippet:
```ruby
class Hash
# Exact method name TBD.
def exchange_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.exchange_value(:k, "new value")
use(old_value)
```
--
https://bugs.ruby-lang.org/