
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-K-V-) and [Kotlin](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-hash-map/pu...) call this `put`. - [Groovy](https://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Map.html) 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%28lib._ra...) calls it `hash-update`. - [Haskell](https://hackage.haskell.org/package/containers-0.4.0.0/docs/Data-Map.html) 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/