elixir

Why forbidden to use a remote function inside a guard


Why I can't to use String or other module in guard?

Code:

def foo(s1, s2) when String.length(s1) == String.length(s2) do 
   # something
end

And how I can elegantly reformat such case, when I wish to use module functions?


Solution

  • From the erlang docs:

    The set of valid guard expressions (sometimes called guard tests) is a subset of the set of valid Erlang expressions. The reason for restricting the set of valid expressions is that evaluation of a guard expression must be guaranteed to be free of side effects.

    The same is also true for Elixir.

    The good news is, for your particular use case, there is a guard that will work:

    def foo(s1, s2) when byte_size(s1) == byte_size(s2) do 
    

    Typically when what you want to do can't be used in a guard, you need to check inside the function, for example:

    def foo(s1, s2) do 
      cond do 
        String.length(s1) == String.length(s2) -> # Do something
        true                                   -> # Do something else
      end
    end
    

    The following answer explains defining your own guard with macros Create new guard clause (the guard must use the valid guard functions documented in https://hexdocs.pm/elixir/patterns-and-guards.html#guards).