Elixir Compile-Time Code Generation
Compile-time code generation builds function definitions from a list while the code is being prepared. One list can produce many functions, each named from one list item.
One list makes two functions
The list holds red and blue. Each name becomes a function.
defmodule Palette do
for name <- [:red, :blue] do
def unquote(name)(), do: Atom.to_string(unquote(name))
end
end
IO.puts(Palette.red())
IO.puts(Palette.blue())Names and values come from pairs
Each pair holds a name and a message. Each pair becomes one function.
defmodule Words do
for {name, message} <- [hello: "Hello!", bye: "Goodbye!"] do
def unquote(name)(), do: unquote(message)
end
end
IO.puts(Words.hello())
IO.puts(Words.bye())Generated functions return numbers too
The same pattern works for numbers, not only for words.
defmodule Scores do
for {name, value} <- [one: 1, two: 2, three: 3] do
def unquote(name)(), do: unquote(value)
end
end
IO.puts(Scores.one())
IO.puts(Scores.two())
IO.puts(Scores.three())Example
defmodule AnimalSounds do
for {name, sound} <- [cat: "Meow", dog: "Woof", cow: "Moo"] do
def unquote(name)(), do: unquote(sound)
end
end
IO.puts(AnimalSounds.cat())
IO.puts(AnimalSounds.dog())
IO.puts(AnimalSounds.cow())Key points
- Code generation: code generation builds definitions from data instead of writing each one by hand.
- List: a list of names drives how many functions are made.
- Use def unquote(name) to define a function whose name comes from a variable.
- Use unquote inside the body to put the list value into the function.
- For: a for loop inside a module runs once per list item and defines one function each time.
In this example, a list of three name and sound pairs drives a for loop, each pair defines one function, and each function returns its own sound.
Note
the generated functions are ordinary functions once they exist.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does def unquote(name) do inside a module?