Elixir Control Flow — if, unless, cond, case, and with
In this tutorial, you will learn about Elixir Control Flow. We cover key concepts, practical examples, and best practices to help you master this topic.
Elixir has fewer control flow constructs than most languages — but each one is more powerful. Because pattern matching is everywhere, you'll reach for case and with more often than if.
In this tutorial, you'll learn every control flow tool in Elixir and when to use each one.
What You'll Learn
- if and unless
- cond for multiple conditions
- case for pattern matching
- with for pipelined matching
- Truthiness and falsiness
if and unless
# if/else (returns a value — everything is an expression)
age = 20
status = if age >= 18, do: "adult", else: "minor"
IO.puts(status) # => adult
# Block form
if age >= 18 do
IO.puts("Welcome!")
else
IO.puts("Access denied")
end
# unless (opposite of if)
unless age < 18 do
IO.puts("Adult") # Runs when condition is false
end
# Only nil and false are falsy — everything else is truthy
if 0, do: IO.puts("truthy") # Runs (0 IS truthy!)
if "", do: IO.puts("also truthy") # Runs
if nil, do: IO.puts("never") # Doesn't run
cond
Use cond when you have multiple conditions (replaces else if chains):
defmodule Grade do
def letter(score) do
cond do
score >= 90 -> "A"
score >= 80 -> "B"
score >= 70 -> "C"
score >= 60 -> "D"
true -> "F" # Default (always matches)
end
end
end
IO.puts(Grade.letter(85)) # => B
case
defmodule HTTP do
def handle_response(status_code) do
case status_code do
200 -> "OK"
201 -> "Created"
301 -> "Moved Permanently"
400 -> "Bad Request"
401 -> "Unauthorized"
403 -> "Forbidden"
404 -> "Not Found"
500 -> "Internal Server Error"
code when code >= 400 -> "Client/Server Error"
_ -> "Unknown"
end
end
end
IO.puts(HTTP.handle_response(404)) # => Not Found
with — Pipeline for Pattern Matches
defmodule Ecommerce do
def checkout(cart_id, user_id) do
with {:ok, cart} <- fetch_cart(cart_id),
true <- cart.items != [],
{:ok, _} <- charge_user(user_id, cart.total),
{:ok, order} <- create_order(user_id, cart) do
{:ok, order}
else
{:error, :not_found} -> {:error, "Cart not found"}
false -> {:error, "Cart is empty"}
{:error, reason} -> {:error, reason}
end
end
defp fetch_cart(id), do: {:ok, %{items: [:a], total: 100}}
defp charge_user(_, _), do: {:ok, :charged}
defp create_order(_, _), do: {:ok, :order_created}
end
IO.inspect(Ecommerce.checkout(1, 1))
Practice Questions
Write a function using
condthat returns a temperature description for 5 ranges.Use
caseto pattern match on different shapes of data: tuples, maps, lists.Write a checkout pipeline using
withthat validates stock, charges, and ships.Find a case where
unlessreads more naturally thanifand write it.Use
condwith atruedefault clause to implement a priority-based system.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro