Cannot use pop_in when the last segment is a map key

Here’s an example of the error:

iex(1)> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
%{"john" => %{age: 27}, "meg" => %{age: 23}}
iex(2)> pop_in(users["john"].age)
** (ArgumentError) cannot use pop_in when the last segment is a map/struct field. This would effectively remove the field :age from the map/struct
    (elixir 1.17.2) lib/kernel.ex:3325: Kernel.nest_pop_in/3
    (elixir 1.17.2) lib/kernel.ex:3311: Kernel.nest_pop_in/2
    (elixir 1.17.2) lib/kernel.ex:3347: Kernel.nest_pop_in/3
    (elixir 1.17.2) expanding macro: Kernel.pop_in/1
    iex:2: (file)
iex(2)> pop_in(users["john"][:age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}

What is the reason behind this limiation? To me both paths look the same, but one works and one doesn’t. And why would removing the field be unexpected in this situation? I thought pop_in is used exactly for this purpose - popping a field from a map.

2 Likes

So I went and asked ChatGPT the same question.

Looks like the reason is that .field access pattern is supposed to be used only in cases where struct/map structure is fixed, so that such access is always safe. However, if you decide to pop that field, then the field will no longer be present, so the semantics are broken.

2 Likes

ChatGPT is correct!

2 Likes