micah
micah

Reputation: 8096

Why Are So Many Guard Expressions in Ifs Illegal?

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 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 think the case is preferred here. But I'd like to understand why this guard expression is illegal. What does erlang see that makes it 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.

Upvotes: 1

Views: 293

Answers (2)

Agus
Agus

Reputation: 689

Well, actually it is not that complex if we carefully read the docs :)

Valid guard expressions are the following:

    - Variables
    - ...

So instead of calling the function maps:is_key inside the if clause, you need to save the value of the function into a variable so that the evaluation of a guard expression can be guaranteed to be free of side effects:

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

Upvotes: 3

Nalin Ranjan
Nalin Ranjan

Reputation: 1782

Not just any function is allowed inside Guard Expressions.

For this particular one, however you can give this a try...

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

WYSIWYG => WHAT YOU SHOW IS WHAT YOU GET

Upvotes: 1

Related Questions