[Proposal] Map.put_new!

86 views
Skip to first unread message

Mário Guimarães

unread,
Jul 24, 2019, 12:47:34 PM7/24/19
to elixir-lang-core
Hello,

presently there is no function that throws an error in case we want to put a really new key in a map.

The function Map.put_new only does nothing if the key is already there.

The idea for Map.put_new! is to throw an error if the key is there. The use case is the developer who wants to be sure that the key is not there, as otherwise it means there is an error in the application code. As such, an exception should be raised.

Is this a useful addition to Map?

Thanks
Mário

Mário Guimarães

unread,
Jul 24, 2019, 1:05:59 PM7/24/19
to elixir-lang-core
It seems this function was proposed here https://github.com/elixir-lang/elixir/pull/5917

and dropped because:

  1. put_new and put_new! pair behaves differently from !-paired functions, I’m not sure if it’s good thing to break expectations in that case.
  2. I don’t feel a huge need for put_new! - put_new itself is already rather rare use case, this one would be even rarer.
Regarding point 1) I can say that Map.replace!/update! also " behaves differently from !-paired functions", yet they still exist

Regarding point 2) well ... there many other functions many of us found very infrequent or no use so far ¯\_(ツ)_/¯

My opinion is that it can be useful to make the code more bulletproof, much like Map.replace!/update! do.

Mário

Ben Wilson

unread,
Jul 25, 2019, 8:04:02 AM7/25/19
to elixir-lang-core
The presence of rarely used functions is not an argument for the addition of further rarely used functions.

José Valim

unread,
Jul 29, 2019, 6:27:07 AM7/29/19
to elixir-l...@googlegroups.com
> 1. put_new and put_new! pair behaves differently from !-paired functions, I’m not sure if it’s good thing to break expectations in that case.

I believe the concern here is that while all functions raise when the key does not exist, the proposed put_new! raises when the key exists. It is how put_new! should behave... but it is a different behaviour than the one that already exists, highlighted by the fact a new exception would have to be added.

Ben commented on the second point already.

Also, your proposal does not include any code examples or snippets on how this pattern would be used. I personally can't recall a need for put_new!, especially because *the best use of "static maps" is by defining all keys upfront and then updating/replacing them*.

José Valim
Skype: jv.ptec
Founder and Director of R&D

Mário Guimarães

unread,
Jul 31, 2019, 1:59:52 PM7/31/19
to elixir-lang-core
I have implemented like this

defmodule KeyFoundError do
  defexception
[:key, :term]
 
def message(%__MODULE__{key: key, term: term}) do
   
"key #{inspect(key)} found in: #{inspect(term)}"
 
end
end


defmodule
MyMap do
 
def put_new!(map, key, value) do
   
if Map.has_key?(map, key) do
     
raise KeyFoundError, key: key, term: map
   
else
     
Map.put(map, key, value)
   
end
 
end
end

and use it to ensure that an algorithm building a map with a non-predefined set of keys fulfills the requirement to write each key only once, which if it is not the case may be a signal that something is wrong with the algorithm.

I agree that this is perhaps only a need in more complex, and thus, less common algorithms, like in my use case, where the keys come from an external data source, and I want to be sure that this is not sending the same key duplicated.

Mário

lostko...@gmail.com

unread,
May 8, 2024, 9:03:35 AMMay 8
to elixir-lang-core

I don't think this will turn the result of this discussion, but I've some comments on:


> I personally can't recall a need for put_new!, especially because *the best use of "static maps" is by defining all keys upfront and then updating/replacing them*.

I've never needed that for "static maps", but I've wanted put_new! a few times with dynamic maps for exactly the opposite of replace!/update!. Consider a server receiving messages for CRUD operations, where entries are identified by some id. On "create" I only want to add a record if no entry for a given id exists (put_new! or first write wins for create) and on "update" I want to make sure an entry for the given id exists to apply the update to.
Reply all
Reply to author
Forward
0 new messages