While learning a new code base, I found that custom guard clause defined with macro defguard is used as function call. As there was no compilation warnings, I investigated more with cursor that provided this code snippet. I like this example simplicity because you only need elixir to run it (I was first introduced with this trick in Sasa Juric's excellent workshop on Elixir Unit testing).
cat > /tmp/test_guard.exs << 'EOF'
defmodule TestGuard do
@list [:a, :b, :c]
defguard is_in_list(x) when x in @list
def test_guard(x) when is_in_list(x), do: "guard: true"
def test_guard(_), do: "guard: false"
def test_body(x) when is_atom(x), do: is_in_list(x)
def test_body(_), do: false
end
IO.puts("Testing guard usage:")
IO.inspect(TestGuard.test_guard(:a))
IO.inspect(TestGuard.test_guard(:d))
IO.puts("\nTesting body usage:")
IO.inspect(TestGuard.test_body(:a))
IO.inspect(TestGuard.test_body(:d))
EOF
elixir /tmp/test_guard.exs
Testing guard usage:
"guard: true"
"guard: false"
Testing body usage:
true
false
Why is this possible? Because:
defguard is_in_list(x) when x in @list
macro is transformed in compile times to two functions:
def is_in_list(x) when x in @list, do: true
def is_in_list(_), do: false