links: Functions in Elixir


Guard Clauses

Guards are used as a complement to pattern matching. They allow for more complex checks. They can be used in some, but not all situations where pattern matching can be used, for example in function clauses and case clauses

def empty?(list) when is_list(list) and length(list) == 0 do
  true
end
  • Guards begin with when keyword, followed by a boolean expression
  • Guard expressions are special functions which:
    • Must be Pure1 and not mutate any global state
    • Must return strict true or false values
  • You can define your own guard with defguard2
    • guard names should start with is_
defmodule HTTP do
  defguard is_success(code) when code >= 200 and code < 300
 
  def handle_response(code) when is_success(code) do
    :ok
  end
end

A function declaration also supports guards and multiple clauses. if a function has several clauses, Elixir will try each clause until it finds one that matches. Here is an implementation that checks if the given number is zero or not

defmodule Math do
  def zero?(0) do
    true
  end
 
  def zero?(x) when is_integer(x) do
    false
  end
end
 
IO.puts Math.zero?(0) # => true
IO.puts Math.zero?(1) # => false
IO.puts Math.zero?([1, 2, 3]) # => ** (FunctionClauseError)
IO.puts Math.zero?(0.0) # => ** (FunctionClauseError)

Giving an argument that does not match any clauses raises an error.

You can write do: to have one-liner functions

defmodule Math do
  def zero?(0) do: true
  def zero?(x) when is_integer(x) do: false
end

tags: elixir guards

sources:


References:

Footnotes

  1. https://gist.github.com/tomekowal/16cb4192b73fe9222de9fd09e653c03e

  2. https://hexdocs.pm/elixir/Kernel.html#defguard/1