ELIXIR / CHAPTER 04

Function clauses and guards

Intermediate

Express domain cases with ordered patterns and supported guard checks.

By the end of this chapter

  • Define a named module function
  • Order specific clauses before general ones
  • Use guards to constrain matched input

The idea

Enter with tuples, atoms, and pattern matching understood. Named functions live in modules and may have several clauses with the same name and arity. Elixir selects the first clause whose pattern and guard match. This makes tagged success and failure values convenient to process directly. A general clause placed too early can hide more specific behavior later in the definition.

Guards refine the accepted values using a restricted set of operations. Checks such as is_integer and numeric comparisons can state a function’s domain clearly. They are not places for arbitrary user-defined function calls. Keep invalid input behavior intentional: provide a fallback when the public contract permits it, or clearly document a narrower accepted domain. The examples use explicit fallback values so the decision is visible.

Elixir example
defmodule Ticket do
  def label(n) when is_integer(n) and n > 0, do: :valid
  def label(_), do: :invalid
end
IO.inspect({Ticket.label(3), Ticket.label(0)})
Result
{:valid, :invalid}

Three satisfies both guard checks. Zero reaches the fallback because it is not strictly positive.

Try it yourself

Define a function with separate clauses for {:ok, value} and {:error, reason}.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

Which guard tests that n is an integer greater than zero?