Issue #20300 has been updated by matheusrich (Matheus Richard).
Some other examples from other languages:
- [
Java](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html#put-… and
[
Kotlin](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-ha…
call this `put`.
- [
Groovy](https://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Map.h… calls
it `putAt`
- [Elixir](https://hexdocs.pm/elixir/1.12/Map.html#get_and_update/3) has an interesting
`get_and_update`, which is very descriptive, but also accepts a function argument, which
can be used to operate on the old value before returning it. I could see us supporting
both cases:
```rb
hash.get_and_update(:key, :new_value)
hash.get_and_update(:key) { |old| old.upcase }
```
- [
Clojure](https://clojuredocs.org/clojure.core/update-in) does something similar with
`update-in`.
-
[
Racket](https://docs.racket-lang.org/reference/hashtables.html#%28def._%28%…
calls it `hash-update`.
- [
Haskell](https://hackage.haskell.org/package/containers-0.4.0.0/docs/Data-M…
calls this `insertLookupWithKey` 😅
---
I like `exchange_value` too. While a bit more verbose, having the `_value` suffix opens
the opportunity to add a similar method for keys in the future
Another suggestion is `replace_value`, since we already have `replace` on hash.
----------------------------------------
Feature #20300: Hash: set value and get pre-existing value in one call
https://bugs.ruby-lang.org/issues/20300#change-107026
* 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/