Intro to Elixir
metaprogramming
First Kyiv Elixir meetup, June 23, 2016
Hello!
I am Anton Mishchuk from Lviv
▧ Ruby Dev at Matic (and we are hiring)
▧ Fan of Elixir programming language
▧ ESpec creator & maintainer
▧ GitHub: antonmi
2
Elixir is Erlang with pretty syntax
and metaprogramming!
What is Elixir?
3
▧ Elixir AST
▧ Quote and unquote
▧ Macroses
▧ DSL
▧ Introspection
What will be about
4
Why metaprogramming
▧ Extending language
▧ Boilerplate removing
▧ Creating DSL
5
Ecto.Schema
Elixir metaprogramming in the wild
Source code
6
Phoenix.Router
Elixir metaprogramming in the wild
Source code
7
ESpec.Let
Elixir metaprogramming in the wild
Source code
8
Initial code parsing
Elixir code
Initial AST
Expansion
Expanded AST
Byte-code generation
Byte-code
Compilation process
Magic is here!
9
Compile-time metaprogramming
▧ Code will not be redefined
▧ Static code analysis still works
▧ No performance penalty
10
Elixir AST. Quoting
‘quote’ macro gets the representation
of any expression.
11
Elixir AST. Quoting
12
▧ The first element is an atom identifying
the operation or another tuple in the same
representation
▧ The second element is a keyword list
containing metadata, like numbers and
contexts
▧ The third element is either a list of
arguments for the function call or an
atom. When this element is an atom, it
means the tuple represents a variable
Elixir AST - 3 element tuple
13
Elixir AST string representation
‘Macro.to_string’ converts the given
expression to a binary
14
Elixir AST evaluation
‘Code.eval_string’ and ‘Code.eval_quoted’
15
Elixir AST. Unquoting
Unquoting is a mechanism to inject code
chunks into quoted expressions.
i.e. inject one AST fragment into another
Let’s try an example:
16
Elixir AST. Unquoting
Trying to evaluate ‘final_expr’
I want to build AST which adds 1 + 2
17
Elixir AST. Unquoting
‘unquote’ helps to inject AST fragment
18
Magic functions - Macros
▧ Macro (which stands for "macroinstruction")
is a programmable pattern which translates
a certain sequence of input into a preset
sequence of output
▧ Macros receive the input AST and must
produce the output AST
▧ The compiler will then simply replace the
macro call with the AST returned from that
macro
▧ Works only at compile time
19
▧ ‘defmodule’, ‘defmacro’, ‘def’, defstruct
▧ ‘require’, ‘import’, ‘use’
▧ ‘If’, ‘unless’, ‘cond’
▧ etc, etc
Macros are everywhere
87% of Elixir code written on Elixir
20
Macros. Example
Calculator
21
Macros. Example
The result is expect. Nothing special.
Because we see completely compiled
code in the iex console
22
Macros. Example
Remember, macros receive quoted
expression and return them
Let’s do what compiler did step by step
23
Macros. Dynamic function definition example
24
Macros. ‘require’ and ‘import’
We should tell the compiler which module
should be compiled before we can use it.
25
‘use’ macro
The simplest way to bring external
functionality into the current lexical scope
26
‘Use’ for DSL
‘Use Ecto.Migration’
‘Ecto.Migration.__using__’
27
‘Use’ for DSL
‘use GenServer’
28
‘Use’ for DSL
‘GenServer.__using__’
29
‘Use’ for DSL
‘use ESpec’
30
‘Use’ for DSL
‘ESpec.__using__’
31
OMG! How to handle all the stuff?
▧ What function/macro I can use in
current scope?
▧ Where does this function/macro come
from?
32
Elixir introspection
▧ __ENV__ : Returns a Macro.ENV struct
containing current environment
information
▧ __MODULE__ : Returns the current
module name as an atom
▧ __DIR__ : Returns the current directory
▧ __CALLER__ : Returns the caller’s
environment information as a Macro.
ENV struct
33
Elixir introspection
‘__ENV__’ in iex
34
And don’t forget about help
‘h IEx.Helpers.b’
35
What is next?
36
With great power comes
great responsibility!
Thank you!
37

Intro to elixir metaprogramming