# Reasoning Behind Illegal If Guard Expression?

I am writing a function that will push a value to a list on a map if the key already exists, or init the key on the map with a new list (containing the pushed element) if it does not already exist.

I tried making this part of the function guard expression but adding this guard expression to the function was illegal. I then tried making this an if but once again the guard expression was illegal. Finally I used a case which was fine.

I believe I’ve read that only a handful of specific BIFs are allowed in function guard expressions, but why is this BIF in the if statement also illegal?

If:

``````map_push(M, R, V) ->
if
maps:is_key(R, M) == true -> #{R := Row} = M, M#{R := [V|Row]};
maps:is_key(R, M) == false -> #{R => [V]}
end.

---

illegal guard expression
%   42|     maps:is_key(R, M) == false -> #{R => [V]}
%     |     ^
``````

Case:

``````map_push(M, R, V) ->
case maps:is_key(R, M) of
true -> #{R := Row} = M, M#{R := [V|Row]};
false -> #{R => [V]}
end.
``````

I think the case is preferred here anyway, but I’d like to understand why this illegal in the if.

3 Likes

What you’re after is in fact `is_map_key/2` , `maps:is_key/2` is not allowed in guard expressions.

In the above you’re not using `maps:is_key/2` as a guard, you’re matching with guards on the result of the call.

I would agree `case` expressions are preferred over `if`, but I also advise the use of function heads before resorting to a case expression in general. Thus :

``````map_push(M, R, V) when is_map_key(R, M) ->
#{R := Row} = M,
M#{R := [V|Row]};

map_push(_M, R, V) ->
#{R => [V]}.
``````

Edit:

Here’s a list of bifs for use in guard expressions : Erlang -- Expressions

3 Likes

Thank you for your response and link to the list of accepted guard BIFs.

I also found this explanation of “side effects” which consider errors as a side effect: [erlang-questions] Side-effects in "if" guards

3 Likes