Bug in Elixir? Map update in guards

Why map update syntax does not work in guards?

1> case [1, 2, 3] of
1>   X when #{x => 1}#{x => 2} =:= #{x => 2} -> X
1> end.


iex> case [1, 2, 3] do
...>   x when %{%{x: 1} | x: 2} == %{x: 2} -> x
...> end

Should I submit it as a bug, or is it intended?


I don’t think that is supported, there’s still a few things in guards that haven’t made it over in the parser, for example I believe map_get is not supported.

map_get is supported because it is a function, not an expression

iex(1)> case %{x: 1} do
...(1)>   x when :erlang.map_get(:x, x) == 1 -> x
...(1)> end
%{x: 1}

IIRC Erlang supports only updates of literal values and I am not sure there is a need for it in Elixir because you could merge them at compile time if you need similar behavior.


What would be the use case for this? Isn’t the above guard checking whether 2 == 2? :thinking:


What do you mean by literal values?

1> X = x.
2> M = #{x => 1}.
3> case 1 of
3>   Y when M#{X => Y} =:= #{x => 1} -> ok
3> end.
1 Like

TIL! That’s news to me. :slight_smile:

It is something we could support then. Is there any use case for it though?

1 Like

I thought about something like

defguard is_same_struct?(left, right) when %{left | meta: nil} == %{right | meta: nil}


defguard equal_request?(left, right) when %{left | timestamp: nil} == %{right | timestamp: nil}

Or even more general and useful example

defguard field_polymorphic?(left_struct, right_struct) when %{left_struct | __struct__: nil} == %{right_struct | __struct__: nil}
1 Like

Hrm… good question. I wonder if that’s indeed the fastest way to compare maps in such scenarios?

How would you compare them the other way? Key-by-key using :maps.iterator?

For a small, known map, I would get the values directly and compare them.

1 Like

This works only if you know all the keys by name.

1 Like