🎓 A1Learner
🔍
0 of 54 lessons completed

Elixir Multiple Clauses

Multiple clauses are several definitions of the same function name, each matching a different pattern. Elixir tries the clauses from top to bottom and runs the first one that matches.

Two atoms pick two different labels

The label function has one clause for :ok and one clause for :error. Each atom matches only its own clause.

defmodule Status do
  def label(:ok), do: "It worked"
  def label(:error), do: "It failed"
end

IO.puts(Status.label(:ok))
IO.puts(Status.label(:error))

A perfect score matches before the catch-all

The clause for 100 sits above the catch-all clause. A score of 100 matches the first clause, and any other score falls through to the second one.

defmodule Grade do
  def label(100), do: "Perfect"
  def label(_score), do: "Keep going"
end

IO.puts(Grade.label(100))
IO.puts(Grade.label(80))

Tuple patterns sort replies into three cases

The first two clauses match result tuples by their first element. The last clause catches every other value.

defmodule Reply do
  def show({:ok, value}), do: "Value: #{value}"
  def show({:error, _reason}), do: "Something went wrong"
  def show(_other), do: "Unknown reply"
end

IO.puts(Reply.show({:ok, 42}))
IO.puts(Reply.show({:error, :bad}))
IO.puts(Reply.show(:hello))

Example

defmodule Shipping do
  def cost(:pickup), do: 0
  def cost(:standard), do: 5
  def cost(:express), do: 15
  def cost(_other), do: 20
end

IO.puts(Shipping.cost(:pickup))
IO.puts(Shipping.cost(:standard))
IO.puts(Shipping.cost(:express))
IO.puts(Shipping.cost(:drone))

Key points

  • Clause: one definition of a function, with its own pattern and result.
  • Same name: clauses share one function name and take the same number of arguments.
  • Pattern: each clause head describes the values that clause accepts.
  • Order: Elixir tries clauses from top to bottom, so the first match wins.
  • Specific first: narrow patterns go above wider patterns that would also match them.
  • Catch-all: a final clause with a plain variable or underscore pattern accepts anything left over.

In this example, each named delivery option matches its own clause and returns its price. The :drone atom matches none of them, so the catch-all clause at the bottom returns 20.

Note

in Elixir, clauses let pattern matching choose the code, instead of a chain of tests inside one body.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A function has def label(100), do: "Perfect" above def label(_score), do: "Keep going". What does label(100) return?