Your macro’s are calling do_my_if
in the ‘callers’ scope, not the macro scope. This is proven by showing that both branches are taken:
iex> import Control
Control
iex> my_if(2==2, do: IO.inspect(true), else: IO.inspect(false))
true
false
true
You can change it to (and should, you cannot make it private because anything a defmacro calls (actually calls, not inside a quote
) needs to be publicly accessible, I’m not sure why but they do) by changing your module to be:
defmodule Control do
defmacro my_if(expr, do: if_block, else: else_block) do
Control.do_my_if(expr, do: if_block, else: else_block)
end
defmacro my_if(expr, do: if_block) do
Control.do_my_if(expr, do: if_block, else: nil)
end
def do_my_if(expr, do: if_block, else: else_block) do
quote do
case unquote(expr) do
result when result in [false, nil] -> unquote(else_block)
_ -> unquote(if_block)
end
end
end
end
Which then results in:
iex> import Control
Control
iex> my_if(2==2, do: IO.inspect(true), else: IO.inspect(false))
true
true
I can detail ‘why’ if curious, but looking over the code and getting it to ‘click’ yourself can often be more enlightening in the tough world of macros.