Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
Elixir in Elixir
Jay Hayes
September 02, 2016
Programming
6
910
Elixir in Elixir
Metaprogramming doesn't have to be scary. Elixir does it really well. Let me show you...
Jay Hayes
September 02, 2016
Tweet
Share
More Decks by Jay Hayes
See All by Jay Hayes
Build Elixir Phoenix
iamvery
0
47
Elixir in Elixir
iamvery
1
130
A Less Complex Web with Ratchet & Jank
iamvery
0
100
Feature. Tests. Implementation.
iamvery
0
52
Ratchet & Jank
iamvery
0
150
Rubyist Does Swift
iamvery
0
51
Swift Introduction
iamvery
0
110
Data Integrity
iamvery
0
67
Pairing with tmux
iamvery
2
140
Other Decks in Programming
See All in Programming
LOWYAの信頼性向上とNew Relic
kazumax55
4
350
TechFeed Conference 2022 - Kotlin Experimental
jmatsu
0
780
スモールチームがAmazon Cognitoでコスパよく作るサービス間連携認証
tacke_jp
2
370
Nix for Scala folks
kubukoz
0
130
Named Document って何?
harunakano
0
380
Micro Frontends with Module Federation: Beyond the Basics @codecrafts2022
manfredsteyer
PRO
0
100
質とスピード(2022春版、質疑応答用資料付き) / Quality and Speed 2022 Spring Edition
twada
PRO
28
18k
2022 FrontEnd Training
mixi_engineers
1
280
偏見と妄想で語るスクリプト言語としての Swift / Swift as a Scripting Language
lovee
2
270
Better Reliability through Observability (and Experimentation)
ksatirli
PRO
1
250
Get Ready for Jakarta EE 10
ivargrimstad
0
2.4k
Is Rust a great language for building Kubernetes ecosystem
deepu105
0
140
Featured
See All Featured
Robots, Beer and Maslow
schacon
152
7.1k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
350
21k
Documentation Writing (for coders)
carmenhchung
48
2.5k
Making Projects Easy
brettharned
98
4.3k
How STYLIGHT went responsive
nonsquared
85
3.9k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
315
19k
Music & Morning Musume
bryan
35
4.1k
Web development in the modern age
philhawksworth
197
9.3k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
100
5.9k
Product Roadmaps are Hard
iamctodd
34
6.1k
Producing Creativity
orderedlist
PRO
333
37k
How to Ace a Technical Interview
jacobian
265
21k
Transcript
Elixir Elixir In
How much?
It depends
What is “Elixir”?
Basics + STDLIB
of Elixir is written in Elixir 78%
Compare to Ruby’s 44%
Numbers? Meh
if
def
|>
Metaprogramming
Code generation
+BZ)BZFT IUUQTJBNWFSZDPNn!JBNWFSZ
None
None
8FEFWFMPQ
8FUFBDI
8FXSJUF
“I’m speaking at ElixirConf!”
“That’s nice. Where is it?”
“Orlando.”
“DISNEY IS THERE!!! CAN WE GO?!”
“Ya, actually it’s at Disney.”
“OMG!!! YOU’RE SPEAKING AT DISNEY?!!”
“Haha, sort of” *interrupted*
*on phone* “YA! He’s speaking at Disney!! We’re GOING!!!” *squeal*
None
None
Metaprogramming
None
programming Meta
Working on Data
data quantities on which operations are performed — Dictionary.app
4 + 2 data
+(4, 2) data
Kernel.+(4, 2)
The program is data
Macros
Macros are everywhere
good macros are invisible
defmodule ItTest do use ExUnit.Case test “works” do assert It.works?
end end macros
Where is the data? Program
defmodule ItTest do use ExUnit.Case test “works” do assert It.works?
end end
defmodule ItTest do use ExUnit.Case test “works” do assert It.works?
end end
defmodule ItTest do use ExUnit.Case test “works” do assert It.works?
end end
defmodule ItTest do use ExUnit.Case test “works” do assert It.works?
end end
Expression macro Expression ✨ ✨
Expression?
“Quoted” Elixir code
{func, …, args}
Abstract Syntax Tree
+ 1 - 2 3
+ 1 - 2 3 ( ( )) func Args
1 + ( 2 - 3 )
Args are quoted
Expression.match?(:lol > :wat) # => false Expression.match?(:lol = :wat) #
=> true
defmacro match?({:=, _, _}) do true end defmacro match?(_expr) do
false end
Expression.match?(:lol > :wat) # => false Expression.match?(:lol = :wat) #
=> true
false # => false true # => true
Must return quoted
defmacro badmatch do {:=, [], [:lol, :wat]} end
defmacro badmatch do quote do :lol = :wat end end
Expression.badmatch # (MatchError)
:lol = :wat # (MatchError)
Quote
{func, meta, args}
{:=, [], [:lol, :wat]}
quote do :lol = :wat end
Sort of like strings…
“1+1”
quote(do: 1+1)
quote do 1+1 end
Return AST of Expression
2 - 3 quote do end
- 2 3 {: , […], [ , ]} (-
2 3)
quote do 1 + (2 - 3) end
{: , […], [ , {: , […], [ ,
]}]} + 1 - 2 3 (+ 1 (- 2 3))
Easier to grok
{:+, […], [1, {:-, […], [2, 3]}]} quote do 1
+ (2 - 3) end
Quoted Literals
quote do: “foo” # “foo” quote do: :foo # :foo
quote do: 1 # 1 quote do: [1] # [1] quote do: {1,2} # {1,2} quote do: [a: 1] # [a: 1]
Unquote
“Inject value in quote”
Like string interpolation
“Inject value into quoted string”
name = “Sue” “hi name” # => “hi name”
name = “Sue” “hi #{name}” # => “hi Sue”
“Inject value into quoted Expression”
num = 42 # => 42 quote do: 1 +
num # => {:+, [], [1, {:num, [], :Elixir}]}
num = 42 # => 42 quote do: 1 +
unquote(num) # => {:+, [], [1, 42]}
name = “Sue” “hi #{name}” # => “hi Sue”
if
if foo > 0 do IO.puts(“Pass!”) else IO.puts(“Fail.”) end
if(…, do: …, else: …)
if(…, [do: …, else: …]) cases cond
Truthy & Falsey
false || nil Falsey
anything else Truthy
case … do x when x in [false, nil] ->
… _ -> … end cond cases
defmacro if(c, do: tc, else: fc) do quote do case
unquote(c) do x when x in [false, nil] -> unquote(fc) _ -> unquote(tc) end end end cond cases cond cases
if do else end foo > 0 IO.puts(“Pass!”) IO.puts(“Fail.”)
case do x when x in [false, nil] -> _
-> end foo > 0 IO.puts(“Fail.”) IO.puts(“Pass!”)
When to macro…
#1 Don’t
Write functions
defmacro add(a, b) do quote do unquote(a) + unquote(b) end
end
def add(a, b) do a + b end
More direct
Less error-prone
#2 Constants
defmacro seconds_per_minute, do: 60 defmacro minutes_per_hour, do: 60
#3 DSL
html do body do div class: “content” do p “Engaging
content.” end end end
#4 Hide details
test “works” do assert It.works? end
#5 Reduce boilerplate
Language extension
defmodule Lolwat do def lol do :wat end end
:elixir_module.compile(Lolwat, {:def, [context: Elixir, import: Kernel], [{:lol, [context: Elixir], Elixir},
[do: :wat]]}, [], __ENV__)
:elixir_module.compile(Lolwat, {:def, [context: Elixir, import: Kernel], [{:lol, [context: Elixir], Elixir},
[do: :wat]]}, [], %{__struct__: Macro.Env, aliases: [], context: nil, context_modules: [Mex], export_vars: nil, file: "iex", function: nil, functions: [Mex: [expand_all: 2], "IEx.Helpers": [c: 1, c: 2, cd: 1, clear: 0, flush: 0, h: 0, i: 1, l: 1, ls: 0, ls: 1, nl: 1, nl: 2, pid: 1, pid: 3, pwd: 0, r: 1, recompile: 0, respawn: 0, v: 0, v: 1], Kernel: [!=: 2, !==: 2, *: 2, +: 1, +: 2, ++: 2, -: 1, -: 2, --: 2, /: 2, <: 2, <=: 2, ==: 2, ===: 2, =~: 2, >: 2, >=: 2, abs: 1, apply: 2, apply: 3, binary_part: 3, bit_size: 1, byte_size: 1, div: 2, elem: 2, exit: 1, function_exported?: 3, get_and_update_in: 3, get_in: 2, hd: 1, inspect: 1, inspect: 2, is_atom: 1, is_binary: 1, is_bitstring: 1, is_boolean: 1, is_float: 1, is_function: 1, is_function: 2, is_integer: 1, is_list: 1, is_map: 1, is_number: 1, is_pid: 1, is_port: 1, is_reference: 1, is_tuple: 1, length: 1, macro_exported?: 3, make_ref: 0, map_size: 1, max: 2, min: 2, node: 0, node: 1, not: 1, pop_in: 2, put_elem: 3, put_in: 3, rem: 2, round: 1, self: 0, send: 2, spawn: 1, spawn: 3, spawn_link: 1, spawn_link: 3, spawn_monitor: 1, spawn_monitor: 3, struct: 1, struct: 2, struct!: 1, struct!: 2, throw: 1, tl: 1, trunc: 1, tuple_size: 1, update_in: 3]], lexical_tracker: nil, line: 2, macro_aliases: [], macros: [Mex: [mex: 1], "IEx.Helpers": [b: 1, h: 1, import_file: 1, import_file: 2, import_file_if_available: 1, import_if_available: 1, import_if_available: 2, s: 1, t: 1], Kernel: [!: 1, &&: 2, ..: 2, <>: 2, @: 1, alias!: 1, and: 2, binding: 0, binding: 1, def: 1, def: 2, defdelegate: 2, defexception: 1, defimpl: 2, defimpl: 3, defmacro: 1, defmacro: 2, defmacrop: 1, defmacrop: 2, defmodule: 2, defoverridable: 1, defp: 1, defp: 2, defprotocol: 2, defstruct: 1, destructure: 2, get_and_update_in: 2, if: 2, in: 2, is_nil: 1, match?: 2, or: 2, pop_in: 1, put_in: 2, raise: 1, raise: 2, reraise: 2, reraise: 3, sigil_C: 2, sigil_D: 2, sigil_N: 2, sigil_R: 2, sigil_S: 2, sigil_T: 2, sigil_W: 2, sigil_c: 2, sigil_r: 2, sigil_s: 2, sigil_w: 2, to_char_list: 1, to_charlist: 1, to_string: 1, unless: 2, update_in: 2, use: 1, use: 2, var!: 1, var!: 2, |>: 2, ||: 2]], module: nil, requires: [IEx.Helpers, Kernel, Kernel.Typespec, Mex], vars: []})
good macros are invisible
CJUMZ&MJYJS.FUB
!JBNWFSZ Questions?