Maps:filter/2 predicate function pattern matching when value is an empty map

Why do the following two expressions not produce the same result?

    State1 = maps:filter(fun(_ Map) -> Map =/= #{} end, State),
    State1 = maps:filter(fun(_ #{}) -> false;
                            (_, _) -> true 
                         end, State),

Probably, I need a day off

1 Like

Aren’t there some commas missing in your function heads?

Because ‘#{}’ means “match any map”. Map pattern match usually includes matching list of keys, in this case that list is empty. If you want, use ‘map_size/1’ BIF in a guard to match an empty map.

Got tricked here few times :smiley:

2 Likes

Elaborating on this, the guard Map =/= #{} compares for non-identity with an empty map, while the match in the function head fun(..., #{}) matches on any map.

2 Likes

This discrepancy between #{} meaning “any map with at least these fields (none, so any map)” and #{} meaning “a map with EXACTLY these fields (none)” came up when I was designing frames. I considered the equivalent of #{ | } – at least these fields – vs #{} – exactly these fields – and indeed being able to say #{ | Rest_Of_Map} looked potentially useful. But #{|} looked ugly. Perhaps #{} – exactly these fields, in all contexts – vs #{…} – at least these fields, only in patterns – would have worked. Too late now.

Sounds good to have both choices, but I actually like that “at least those fields” is the default behavior because you can add fields to maps without breaking working code. #{ | Rest_Of_Map} looks interesting, would it be equivalent to:

#{f1:=F1, f2:=F2} = Map,
Rest_Of_Map = maps:without([f1,f2],Map).

?

Maybe syntax for “exactly those fields” could be a thing, but not with #{} syntax? Because of the current behavior it seems pretty hard with to come up with syntax that is backward compatible and makes sense in matching “exactly those fields”.