Lab Zero Innovations Inc.
77 Battery Street
San Francisco, CA 94111
415.839.6861
info@labzero.com
labzero.com
Introduction to Elixir
Brien Wankel
Sasha Voynow
What is Elixir?
Elixir is a dynamic, functional language designed for building scalable and
maintainable applications.
Elixir leverages the Erlang VM, known for running low-latency, distributed
and fault-tolerant systems, while also being successfully used in web
development and the embedded software domain.
● First release: 2012
● 1.0 in September 2014
● Takes advantage of the Erlang VM
○ Compiled to Erlang (BEAM) bytecode
○ Runs on the Erlang (BEAM) VM
Wait, did you say Erlang?
● Created in 1986 by Ericsson for telco exchange software
● Open Source since 1988
● A VM (BEAM)
● A set of libraries and tools (OTP)
● Engineered for
○ Fault tolerance (uptime!)
○ Responsiveness (low latency!)
○ Distributed computing (clustering! concurrency!)
Open Telecom Platform (OTP)
Search YouTube for: “Erlang: The Movie”
OTP
● a set of tools and libraries for implementing fault tolerant server
applications
● Some OTP jargon
○ Process: An extremely lightweight unit of execution
○ Application: A tree/graph of processes that are managed
together.
○ Project: What is normally thought of as an application. A
number of applications started together in the same VM
OSS in Erlang
Erlang in Production
If Erlang is so great, why Elixir?
Erlang has some UX issues
○ Funky, unfamiliar syntax
○ Lots of boilerplate
% module_name.erl
-module(module_name). % you may use some other name
-compile(export_all).
hello() ->
io:format("~s~n", ["Hello world!"]).
# module_name.ex
defmodule ModuleName do
def hello do
IO.puts "Hello World"
end
end
Elixir in Production
Types
The Usual Suspects
● Value Types
○ Int
○ Float
○ Atom :yo
○ String / Binary
● Container Types
○ Tuple {1, :foo}
○ List [1,2,3]
○ Map %{foo: 10, bar: "baz" “foo” => “figgle”}
○ Struct
■ a named or tagged Map
■ %User{name: "Brien Wankel", company: "Lab Zero"}
● and some misc others
Pattern
M
atching
The Match Operator (=)
iex(1)> 3 = 3
3
iex(2)> x = 3
3
iex(3)> 3 = x
3
iex(4)> 2 = x
** (MatchError) no match of right hand side value: 3
The Pin Operator (^)
iex(1)> x = 3
3
iex(2)> y = x
3
iex(3)> x = 10
10
iex(4)> y
3
iex(5)> ^x = 3
** (MatchError) no match of right hand side value: 3
iex(5)> ^x = 10
10
Matching Lists
iex(1)> [a,b,c] = [1,2,3]
[1, 2, 3]
iex(2)> a
1
iex(3)> b
2
iex(4)> c
3
iex(1)> [h | t] = [1,2,3]
[1, 2, 3]
iex(2)> h
1
iex(3)> t
[2, 3]
Matching Maps
iex(1)> user = %{name: "Brien", status: :expired, state: "AZ"}
%{name: "Brien", state: "AZ", status: :expired}
iex(2)> %{name: theName} = user
%{name: "Brien", state: "AZ", status: :expired}
iex(3)> theName
"Brien"
iex(4)> %{name: theName, state: "CA"} = user
** (MatchError) no match of right hand side value: %{name:
"Brien", state: "AZ", status: :expired}
Matching in case statements
def registered_users do
case load_users_from_database() do
{:ok, users} -> users
{:err, error}
-> IO.puts("something went wrong: #{error}")
[]
end
end
def charge_user(user) do
case user do
%User{account_type: :premium} -> charge_card(user)
_ -> nil
end
end
Functions
# different functions
# &Lunchdown.string_to_int/1
def string_to_int(x) do
# ...
end
# &Lunchdown.string_to_int/2
def string_to_int(x, radix) do
# ...
end
# multiple heads of the same function
# &Lunchdown.find/1
def find([_h | _t] = ids) do
# ...
end
def find(id) do
# ...
end
Matching in Function Definitions
def handle_cast(:increment, state) do
{:noreply, state + 1}
end
def handle_cast(:decrement, state) do
{:noreply, state - 1}
end
def charge_credit_card(user = %User{account_type: :premium}) do
# charge the credit card
end
def charge_credit_card(_) do
# no-op
end
Matching in Function Definitions
# recursion
def sum([]), do: 0
def sum*([h | t]) do
h + sum(t)
end
Guard clauses
* You can only use a subset of built-in functions and operators
def charge_credit_card(cc_number, amount) when amount < 0, do: end
def charge_credit_card(cc_number, amount) do
# do some stuff
end
Pipelines and the |> operator
● A common elixir idiom for composing functions
● Building up complex transformations of data out of simpler ones in a way
that is readable and intention revealing
● APIs are commonly designed to work well with pipelines
Pipelines
def user_by_uid(uid) do
Authorization
|> where([a], a.uid == ^uid)
|> join(:inner, [a], u in User, u.id == a.user_id)
|> preload(:user)
|> Repo.one
end
def word_count(filename) do
increment = fn x -> x + 1 end
count_fun = fn w, m -> Map.update(m, w, 1, increment) end
filename
|> File.stream!
|> Stream.map(&String.trim/1)
|> Stream.flat_map(&String.split/1)
|> Stream.map(&String.downcase/1)
|> Enum.reduce(%{}, count_fun)
end
Modules
● The unit of code organization in Elixir
● Just a group of related functions.
defmodule Stack do
defstruct [:items]
# this defines a struct %Stack with the field items
def init do
%Stack{items: []}
end
def push(%Stack(items: items}, item), do: %Stack{items: items ++ [item]}
def pop(%Stack{items: [h | t]}), do: {:ok, h, %Stack{items: t}}
def pop(%Stack{items: []}), do: {:err, "no items"}
end
Elixir Ecosystem Highlights
● mix / hex
● Phoenix Framework
● ecto
● nerves
● distillery / edeliver
Further info
● elixir-lang.org
● hex.pm
● phoenix-framework.org
● Elixir Sips
● Google: “awesome elixir”
● elixirstatus.com
Thank you
info@labzero.com

Introduction to Elixir

  • 1.
    Lab Zero InnovationsInc. 77 Battery Street San Francisco, CA 94111 415.839.6861 info@labzero.com labzero.com Introduction to Elixir Brien Wankel Sasha Voynow
  • 3.
    What is Elixir? Elixiris a dynamic, functional language designed for building scalable and maintainable applications. Elixir leverages the Erlang VM, known for running low-latency, distributed and fault-tolerant systems, while also being successfully used in web development and the embedded software domain. ● First release: 2012 ● 1.0 in September 2014 ● Takes advantage of the Erlang VM ○ Compiled to Erlang (BEAM) bytecode ○ Runs on the Erlang (BEAM) VM
  • 4.
    Wait, did yousay Erlang? ● Created in 1986 by Ericsson for telco exchange software ● Open Source since 1988 ● A VM (BEAM) ● A set of libraries and tools (OTP) ● Engineered for ○ Fault tolerance (uptime!) ○ Responsiveness (low latency!) ○ Distributed computing (clustering! concurrency!)
  • 5.
    Open Telecom Platform(OTP) Search YouTube for: “Erlang: The Movie”
  • 6.
    OTP ● a setof tools and libraries for implementing fault tolerant server applications ● Some OTP jargon ○ Process: An extremely lightweight unit of execution ○ Application: A tree/graph of processes that are managed together. ○ Project: What is normally thought of as an application. A number of applications started together in the same VM
  • 8.
    OSS in Erlang Erlangin Production
  • 9.
    If Erlang isso great, why Elixir? Erlang has some UX issues ○ Funky, unfamiliar syntax ○ Lots of boilerplate % module_name.erl -module(module_name). % you may use some other name -compile(export_all). hello() -> io:format("~s~n", ["Hello world!"]). # module_name.ex defmodule ModuleName do def hello do IO.puts "Hello World" end end
  • 10.
  • 11.
  • 12.
    The Usual Suspects ●Value Types ○ Int ○ Float ○ Atom :yo ○ String / Binary
  • 13.
    ● Container Types ○Tuple {1, :foo} ○ List [1,2,3] ○ Map %{foo: 10, bar: "baz" “foo” => “figgle”} ○ Struct ■ a named or tagged Map ■ %User{name: "Brien Wankel", company: "Lab Zero"} ● and some misc others
  • 14.
  • 15.
    The Match Operator(=) iex(1)> 3 = 3 3 iex(2)> x = 3 3 iex(3)> 3 = x 3 iex(4)> 2 = x ** (MatchError) no match of right hand side value: 3
  • 16.
    The Pin Operator(^) iex(1)> x = 3 3 iex(2)> y = x 3 iex(3)> x = 10 10 iex(4)> y 3 iex(5)> ^x = 3 ** (MatchError) no match of right hand side value: 3 iex(5)> ^x = 10 10
  • 17.
    Matching Lists iex(1)> [a,b,c]= [1,2,3] [1, 2, 3] iex(2)> a 1 iex(3)> b 2 iex(4)> c 3 iex(1)> [h | t] = [1,2,3] [1, 2, 3] iex(2)> h 1 iex(3)> t [2, 3]
  • 18.
    Matching Maps iex(1)> user= %{name: "Brien", status: :expired, state: "AZ"} %{name: "Brien", state: "AZ", status: :expired} iex(2)> %{name: theName} = user %{name: "Brien", state: "AZ", status: :expired} iex(3)> theName "Brien" iex(4)> %{name: theName, state: "CA"} = user ** (MatchError) no match of right hand side value: %{name: "Brien", state: "AZ", status: :expired}
  • 19.
    Matching in casestatements def registered_users do case load_users_from_database() do {:ok, users} -> users {:err, error} -> IO.puts("something went wrong: #{error}") [] end end def charge_user(user) do case user do %User{account_type: :premium} -> charge_card(user) _ -> nil end end
  • 20.
    Functions # different functions #&Lunchdown.string_to_int/1 def string_to_int(x) do # ... end # &Lunchdown.string_to_int/2 def string_to_int(x, radix) do # ... end # multiple heads of the same function # &Lunchdown.find/1 def find([_h | _t] = ids) do # ... end def find(id) do # ... end
  • 21.
    Matching in FunctionDefinitions def handle_cast(:increment, state) do {:noreply, state + 1} end def handle_cast(:decrement, state) do {:noreply, state - 1} end def charge_credit_card(user = %User{account_type: :premium}) do # charge the credit card end def charge_credit_card(_) do # no-op end
  • 22.
    Matching in FunctionDefinitions # recursion def sum([]), do: 0 def sum*([h | t]) do h + sum(t) end
  • 23.
    Guard clauses * Youcan only use a subset of built-in functions and operators def charge_credit_card(cc_number, amount) when amount < 0, do: end def charge_credit_card(cc_number, amount) do # do some stuff end
  • 24.
    Pipelines and the|> operator ● A common elixir idiom for composing functions ● Building up complex transformations of data out of simpler ones in a way that is readable and intention revealing ● APIs are commonly designed to work well with pipelines
  • 25.
    Pipelines def user_by_uid(uid) do Authorization |>where([a], a.uid == ^uid) |> join(:inner, [a], u in User, u.id == a.user_id) |> preload(:user) |> Repo.one end def word_count(filename) do increment = fn x -> x + 1 end count_fun = fn w, m -> Map.update(m, w, 1, increment) end filename |> File.stream! |> Stream.map(&String.trim/1) |> Stream.flat_map(&String.split/1) |> Stream.map(&String.downcase/1) |> Enum.reduce(%{}, count_fun) end
  • 26.
    Modules ● The unitof code organization in Elixir ● Just a group of related functions. defmodule Stack do defstruct [:items] # this defines a struct %Stack with the field items def init do %Stack{items: []} end def push(%Stack(items: items}, item), do: %Stack{items: items ++ [item]} def pop(%Stack{items: [h | t]}), do: {:ok, h, %Stack{items: t}} def pop(%Stack{items: []}), do: {:err, "no items"} end
  • 27.
    Elixir Ecosystem Highlights ●mix / hex ● Phoenix Framework ● ecto ● nerves ● distillery / edeliver
  • 28.
    Further info ● elixir-lang.org ●hex.pm ● phoenix-framework.org ● Elixir Sips ● Google: “awesome elixir” ● elixirstatus.com
  • 29.