Elixir Language

basic use of guard clauses

basic uses of guard clauses

In Elixir, one can create multiple implementations of a function with the same name, and specify rules which will be applied to the parameters of the function before calling the function in order to determine which implementation to run.

These rules are marked by the keyword when, and they go between the def function_name(params) and the do in the function definition. A trivial example:

defmodule Math do

  def is_even(num) when num === 1 do
    false
  end
  def is_even(num) when num === 2 do
    true
  end

  def is_odd(num) when num === 1 do
    true
  end
  def is_odd(num) when num === 2 do
    false
  end

end

Say I run Math.is_even(2) with this example. There are two implementations of is_even, with differing guard clauses. The system will look at them in order, and run the first implementation where the parameters satisfy the guard clause. The first one specifies that num === 1 which is not true, so it moves on to the next one. The second one specifies that num === 2, which is true, so this is the implementation that is used, and the return value will be true.

What if I run Math.is_odd(1)? The system looks at the first implementation, and sees that since num is 1 the guard clause of the first implementation is satisfied. It will then use that implementation and return true, and not bother looking at any other implementations.

Guards are limited in the types of operations they can run. The Elixir documentation lists every allowed operation; in a nutshell they allow comparisons, math, binary operations, type-checking (e.g. is_atom), and a handful of small convenience functions (e.g. length). It is possible to define custom guard clauses, but it requires creating macros and is best left for a more advanced guide.


Note that guards do not throw errors; they are treated as normal failures of the guard clause, and the system moves on to look at the next implementation. If you find that you’re getting (FunctionClauseError) no function clause matching when calling a guarded function with params you expect to work, it may be that a guard clause which you expect to work is throwing an error which is being swallowed up.

To see this for yourself, create and then call a function with a guard which makes no sense, such as this which tries to divide by zero:

defmodule BadMath do
  def divide(a) when a / 0 === :foo do
    :bar
  end
end

Calling BadMath.divide("anything") will provide the somewhat-unhelpful error (FunctionClauseError) no function clause matching in BadMath.divide/1 — whereas if you had tried to run "anything" / 0 directly, you would get a more helpful error: (ArithmeticError) bad argument in arithmetic expression.


This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow