Elixir
“If Java is 'write once, run anywhere', then Erlang is 'write once, run forever'.”
- Joe Armstrong
“ The AXD301 has achieved a NINE nines reliability (yes, you read that right, 99.9999999%). Let’s put this in context: 5 nines is reckoned to be good (5.2 minutes of downtime/year). 7 nines almost unachievable ... but we did 9.
Why is this? No shared state, plus a sophisticated error recovery model. “
- Joe Armstrong
“ Last June a presentation at the Code BEAM conference noted that every year Cisco ships about two million devices with Erlang, and that 90% of all internet traffic goes
through Erlang controlled nodes “
- Joe Armstrong
Varför Elixir?
Erlang är gammalt :(
Erlang |> Ruby :: ❤ Elixir ❤
-
pipes
-
concurrency
-
scalability
-
sigils
-
function guards
-
underbar syntax
-
pattern matching
-
meta-programming
-
readable regex
-
doctests
“Programming should be about transformation of data.”
# Utan pipes
String.replace(String.trim(String.downcase(" HEJSAN! ")), "san!", "")
# Med pipes
" HEJSAN! "
|> String.downcase()
|> String.trim()
|> String.replace("san!", "")
# hej
Pipes
def get_user_data(user) do
Api.get_data(user)
|> filter_sensitive_info()
|> IO.inspect()
|> add_timestamps()
|> downcase_username()
end
Erlang |> Ruby :: ❤ Elixir ❤
-
immutability
-
pipes
-
-
concurrency
-
scalability
-
sigils
-
function guards
-
underbar syntax
-
meta-programming
-
readable regex
-
doctests
-
pattern matching
Rethinking assignment
user = {"Alexander", "iteam"}
{"Alexander", employer} = user
IO.puts(employer)
# iteam
{"Andreas", employer} = user
# == Compilation error in file lib/test.ex ==
# ** (MatchError) no match of right hand side value: {"Andreas", "iteam"}
# lib/test.ex:22: Test.greet/0
# (elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7
Pattern matching
def greet(), do: IO.puts "hejsan anonym!"
def greet("Stefan"), do: IO.puts "Nämen, hallå hallå!"
def greet("Christian"), do: IO.puts "God afton direktören!"
greet()
# hejsan anonym!
greet("Stefan")
# Nämen, hallå hallå!
greet("Christian")
# God afton direktören!
def greet([]), do: IO.puts "Det finns ingen att hälsa på!"
def greet([first | tail]),
do: IO.puts "Nämen, hallå #{first} och #{tail}.."
greet([])
# Det finns ingen att hälsa på :(
greet(["Andreas", "Kristoffer", "Maria", "Izabella"])
# Nämen, hallå Andreas och KristofferMariaIzabella..
def greet(["Stefan" | tail]),
do: IO.puts "Nämen, hallå Stefan och #{tail}.."
def greet([_first | _tail]),
do: IO.puts "Jag vill hälsa på Stefan först ju.."
greet(["Emma-Klara", "Maria", "Izabella", "Stefan"])
# Jag vill hälsa på Stefan först ju..
greet(["Stefan", "Emma-Klara", "Maria", "Izabella"])
# Nämen, hallå Stefan och Emma-KlaraMariaIzabella..
def greet([]), do: :ok
def greet([first | []]),
do: IO.puts "Sist men inte minst, hallå #{first}!"
def greet([first | tail]) do
IO.puts "Hallå #{first}!"
greet(tail)
end
greet(["Emil", "Mikaela", "Erik", "Alexander"])
# Hallå Emil!
# Hallå Mikaela!
# Hallå Erik!
# Sist men inte minst, hallå Alexander!
Pattern matching
(lite) mer användbart
use-case
Railway Oriented
def create(params) do
%User{}
|> parse_firstname(params["firstname"])
|> parse_lastname(params["lastname"])
|> parse_age(params["age"])
end
def parse_lastname({:error, _} = err, _name), do: err
def parse_lastname(user, nil), do: {:error, "name is required"}
def parse_lastname(user, ""), do: parse_lastname(user, nil)
def parse_lastname(user, name), do: %{user | lastname: name}
def create(params) do
with {:ok, firstname} <- parse_firstname(params["firstname"]),
{:ok, lastname} <- parse_lastname(params["lastname"])
{:ok, age} <- parse_age(params["age"])
do
%User{firstname: firstname, lastname: lastname, age: age }
else
err -> err
end
end
def parse_lastname(nil), do: {:error, "name is required"}
def parse_lastname(""), do: parse_lastname(nil)
def parse_lastname(name), do: {:ok, name}
Doc tests
defmodule Test do
@doc ~S"""
Says Hallå to the first element of the list
## Examples
iex> Test.greet(["Rebecca"])
"Hallå Rebecca!"
iex> Test.greet(["Martin", "Rebecca"])
"Hallå Martin!"
"""
def greet([first | _]) do
"Hallå #{first}!"
end
end
Underbar Syntax
### Språkkonventioner från verkliga livet
def is_night? (argument) do
argument === "MOON"
end
def do_the_thing! do
raise "Not possible"
end
### function guards
def is_night? (argument) when is_string(argument) do
argument === "MOON"
end
def is_night? (_)
false
end
### Sigils
naive_date = ~N{2000-01-01 23:00:07}
# Ett Date-object
~r{foo|bar}
# Regex
~w{foo bar baz}
# ["foo", "bar", "baz"]
### Inga instance-methods, konsekvent och lätt att pipe:a
Enum.map(...)
String.replace(...)
"Just let it crash"
- Unknown
-
Self healing
-
Distributed Load
-
Scalable
När?
- Ett sundare språk än JavaScript
- Mer skalbart
- Slipper extra services
När ska man inte använda det?
Phoenix
Ruby on Rails 2.0 (bildligt talat)
- Mycket av communityn från RoR
- "database abstraction layer, Templates, Scaffolding a-la RoR
- Live View
- Explicit > Implicit
- Concurrency as a feature
Slutord
Tack!
Om du vill veta mer:
How Discord scaled Elixir to 5 000 000 concurrent users:
https://blog.discordapp.com/scaling-elixir-f9b8e1e7c29b
Compiling Elixir to WebAssembly:
https://github.com/lumen/lumen
PhoenixPhrenzy:
Programming Elixir, Dave Thomas
deck
By Mikael Gråborg
deck
- 157