Understanding if, else

I have been playing with if else statements as well as ternary statements and I came across the following.

def if_test(bool) do
  if bool, do: IO.puts "First IF",
    if bool, do: IO.puts "This is never reached",
    else: IO.puts "Second ELSE"

|> Second ELSE
** (CaseClauseError) no case clause matching: {"This is never reached"}

if(false)    # Does not print anything.

I expected that when true was passed it would have printed “First IF” and when false “Second ELSE” printed. Why is this behaviour not occuring?

If you run that code through the formatter you’ll see that what you actually have here is:

def if_test(bool) do
  if bool,
      IO.puts("First IF",
              IO.puts("This is never reached",
                else: IO.puts("Second ELSE")

Your IO.puts needs parens, otherwise what you have is IO.puts("First IF", else, ...)


Also where you choose to put your IO.puts suggests you are still in the statement mindset, rather than an expression mindset.

Compare to:

defmodule Demo do
  def if_test(test) do
    if(test, do: "First IF", else: if(test, do: "This is never reached", else: "Second ELSE"))


I have been playing with if else statements as well as ternary statements

It may help in your thinking (and communication) if you start to more clearly draw the line between the concept of a statement and an expression.

  • an expression has to evaluate to a value
  • a statement simply “does” something (which may include evaluating expressions) which often includes some sort of side effect.

The ternary operator is always part of an expression, so it always has to provide a value (or evaluate an expression) for both cases. In JavaScript if is a statement (not an expression) so the else branch is entirely optional.

In Elixir if is an expression. And while you don’t have to provide an else - it is always there; an absent else is interpreted as "evaluate to nil".

The sooner you get that straight the better, otherwise you’ll end up looking at errors like this one.