case

case is Elixir’s most common branching construct. You hand it a value, a list of patterns, and the block that belongs to the first pattern that matches runs. For many Elixir programmers it is the go-to tool whenever a branch depends on the shape or the content of a value.

case relies on pattern matching, Elixir’s way of comparing a value against a shape (a number, an atom, a tuple, a list, and so on). The examples here show the basic idea. The Pattern Matching chapter covers the full story.

A case expression evaluates an expression, and compares the result to each pattern specified in the clauses. When a match is found, the associated block of code is executed.

iex> num = 2
iex> case num do
...>   1 ->
...>     IO.puts("One")
...>   2 ->
...>     IO.puts("Two")
...>   _ ->
...>     IO.puts("Other")
...> end
Two

In the above example, num is evaluated and its value is compared with each pattern. The pattern 2 matches the value of num, so "Two" is printed.

A catch-all clause (_ →) is often used as the last clause to handle any values not explicitly covered by previous patterns.

Pattern matching in case is not limited to simple values. You can also pattern match on more complex structures like tuples, lists, or maps.

iex> tuple = {:ok, "Success"}
iex> case tuple do
...>   {:ok, msg} ->
...>     IO.puts("Operation successful: #{msg}")
...>   {:error, reason} ->
...>     IO.puts("Operation failed: #{reason}")
...>   _ ->
...>     IO.puts("Unknown response")
...> end
Operation successful: Success

In this example, the case statement matches on the structure and content of the tuple.

Remember, like if and unless, case is an expression, meaning it returns a value which can be assigned to a variable or used in another expression.

iex> num = 3
iex> result = case num do
...>   1 ->
...>     "One"
...>   2 ->
...>     "Two"
...>   _ ->
...>     "Other"
...> end
iex> IO.puts(result)
Other

In this example, we use a case expression to evaluate num and assign the corresponding string to the result variable. The variable result is then printed using IO.puts/1. The case expression returns "Other", because num does not match 1 or 2, and "Other" is assigned to result.

Importance of Pattern Order

A critical aspect to understand when using case is the order of pattern matches. Elixir evaluates the patterns from top to bottom and executes the first pattern that matches, ignoring any subsequent patterns even if they are more precise.

Let’s illustrate this with an example:

iex> tuple = {:ok, "Success"}
iex> case tuple do
...>   {:ok, _} ->
...>     IO.puts("Operation was OK")
...>   {:ok, msg} ->
...>     IO.puts("Operation successful: #{msg}")
...>   _ ->
...>     IO.puts("Unknown response")
...> end
Operation was OK

In this example, even though the second pattern {:ok, msg} is a better match for tuple (as it also matches and binds the message), the first pattern {:ok, _} matches first and so its associated code is executed.

Therefore, when using case, it’s important to order your patterns from the most specific to the least specific to ensure the intended pattern is matched first.