Why do functions inside a keywords list passed as arguments to `if` aren't called immediately?

Why do functions inside the keywords list passed as arguments to if aren’t called immediately? Is this unique to if?

# example.exs
defmodule Call do
  def this(), do: IO.puts("this")
  def that(), do: IO.puts("that")
end

defmodule Example do
  def fun(keywords), do: :ok
end

IO.puts(
  Example.fun(
    [do: Call.this(), else: Call.that()]
  )
)

IO.puts(
  if(
    true,
    [do: Call.this(), else: Call.that()]
  )
)

Output from file:

$ elixir example.exs
this
that
ok
this # expected 'this' and 'that' always to be called independently of the if the boolean evaluation
ok

if is not a function, it is a macro. Macros run at compile-time and receive the AST representation of their arguments without any evaluation.

The guide has a good example of implementing an if-like macro:

2 Likes

Thanks! :slight_smile:

If it was written like this, would you still expect both to be called?

IO.puts(
  if true do
    Call.this()
  else
    Call.that()
  end
)

I suppose not, because what would be the point of if then? But both of these codes are equivalent. In fact the latter is just syntax sugar for the former.

No, from the syntax sugar the logic flow is clear. My doubt came from reading Optional Syntax Sheet - Getting Started.

My question was about why the two codes work differently even though they are the same and not about how can I make sense of this. :slight_smile: