Elixir by Example

case, cond and if

Edit any cell and run it in your browser Download source

case matches a value against patterns, top to bottom. Clauses can have guards.

classify = fn value ->
  case value do
    0 -> "zero"
    n when is_integer(n) and n < 0 -> "negative"
    n when is_integer(n) -> "positive"
    _ -> "not an integer"
  end
end

IO.inspect(Enum.map([0, -5, 7, :x], classify))
["zero", "negative", "positive", "not an integer"]

No clause matching raises CaseClauseError.

try do
  case :maybe do
    :yes -> 1
    :no -> 2
  end
rescue
  e in CaseClauseError -> IO.puts(Exception.message(e))
end
no case clause matching:

    :maybe

cond picks the first condition that's truthy. Useful when you test conditions, not shapes.

fizzbuzz = fn n ->
  cond do
    rem(n, 15) == 0 -> "FizzBuzz"
    rem(n, 3) == 0 -> "Fizz"
    rem(n, 5) == 0 -> "Buzz"
    true -> n
  end
end

IO.inspect(Enum.map(1..15, fizzbuzz))
[1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14,
 "FizzBuzz"]

if and unless handle a single condition. Everything is an expression, so they return values. Without else, a false if returns nil.

temp = 31
label = if temp > 30, do: "hot", else: "fine"
IO.inspect(label)
IO.inspect(if false, do: :never)
"hot"
nil

Variables bound inside if, case or cond don't leak out. Bind the result instead.

count = 0

count =
  if temp > 30 do
    count + 1
  else
    count
  end

IO.inspect(count)
1

Pitfall: rebinding inside a block doesn't change the outer variable. if x, do: count = count + 1 leaves count unchanged afterwards (and Elixir warns the inner variable is unused). Always write count = if ..., do: ..., else: ....

Pitfall: reaching for nested ifs is usually a sign you want case on a tuple, or multiple function clauses.