Control flow structures

Leap
Leap in Elixir
defmodule Year do
  @spec leap_year?(non_neg_integer) :: boolean
  def leap_year?(year) do
    if rem(year, 100) == 0 do
      rem(year, 400) == 0
    else
      rem(year, 4) == 0
    end
  end
end

If

Elixir provides four control flow structures: case, cond, if, and unless.

The if and unless allow to evaluate only one condition. Unlike in many other languages, there is no else if option in Elixir.

However, in this case, it is not necessary. We can use if once to check if the year is divisible by 100. If it is, then whether it is a leap year or not depends on if it is divisible by 400. If it is not, then whether it is a leap year or not depends on if it is divisible by 4.

def leap_year?(year) do
  if rem(year, 100) == 0 do
    rem(year, 400) == 0
  else
    rem(year, 4) == 0
  end
end

Cond

Another option is cond which allows for evaluating multiple conditions, similar to else if in other languages.

def leap_year?(year) do
  cond do
    rem(year, 400) == 0 -> true
    rem(year, 100) == 0 -> false
    rem(year, 4) == 0 -> true
    true -> false
  end
end

Similarly to the multiple clause function approach, the order here matters. The conditions are evaluated in order, and the first that is not nil or false leads to the result.

Case

case allows to compare a value to multiple patterns, but can also replicate what if offers.

def leap_year?(year) do
  case rem(year, 100) do
    0 -> rem(year, 400) == 0
    _ -> rem(year, 4) == 0
  end
end

It also supports guards, offering another way to solve the problem.

def leap_year?(year) do
  case year do
    _ when rem(year, 400) == 0 -> true
    _ when rem(year, 100) == 0 -> false
    _ when rem(year, 4) == 0 -> true
    _ -> false
  end
end

The case can be very flexible, so many variations are possible. Using it with pattern matching on a tuple is considered the most idiomatic. In this case, a tuple is created with all the checks. Then, pattern matching to tuples is performed.

def leap_year?(year) do
  case {rem(year, 400), rem(year, 100), rem(year, 4)} do
    {0, _, _} -> true
    {_, 0, _} -> false
    {_, _, 0} -> true
    _ -> false
  end
end
16th Oct 2024 · Found it useful?