My interest is in application development so macros are not something I expect to ever be creating. So this is mostly a chapter for reading.
Did work through the first two exercises. Took awhile for me to understand that I cannot use a macro-defined function in the module where it was expanded. Makes sense since Elixir first compiles then loads, so the dynamically-created function isn’t available for use.
Never use a macro when you could use a function. Macros can make your code harder to understand.
Macros are useful when you need to delay parameter evaluation.
The
require
call ensures a module is compiled before the current one.- Watch for circular references!
Macro definitions cannot be used in the file in which they are defined.
When you define a new function with a macro, you cannot use that function in the same module.
MacrosAndCodeEvaluation-1
Write a macro called myunless
that implements the standard unless
functionality.
defmodule My do
@moduledoc """
My.unless true do
"Truth"
else
"Falsity"
end
"""
defmacro unless(condition, clauses) do
do_clause = Keyword.get(clauses, :do, nil)
else_clause = Keyword.get(clauses, :else, nil)
quote do
case unquote(condition) do
val when val in [false, nil] -> unquote(else_clause)
_ -> unquote(do_clause)
end
end
end
end
require My
My.unless 1==1 do
"hello"
else
"goodbye"
end
MacrosAndCodeEvaluation-2
Write a macro times_n
.
defmodule Times do
@moduledoc """
Times.times_n(3) creates a times_3 function.
"""
defmacro times_n(n) do
func = String.to_atom("times_#{n}")
quote do
def unquote(func)(value), do: value * unquote(n)
end
end
end
defmodule Test do
require Times
Times.times_n(3)
Times.times_n(5)
end
IO.puts Test.times_3(4)
All notes and comments are my own opinion. Follow me at @rgacote@genserver.social