About Me
@qhwa on
creator of
worked at Alibaba
now at Helijia.com
Slide 3
Slide 3 text
About Me
work in web industry since 2004
built web products with Ruby since
2011
use Elixir since 2016
Slide 4
Slide 4 text
I ❤ Building Web
Products
Slide 5
Slide 5 text
I ❤ Ruby
program happily
high productivity
easy to transform minds to codes
high maintainability
easy to write expressive and clean codes
amazing community
Slide 6
Slide 6 text
But Ruby does not fit
in all situations.
Slide 7
Slide 7 text
No content
Slide 8
Slide 8 text
Erlang
Slide 9
Slide 9 text
1980s
for telecom companies
still a general-purpose language
Slide 10
Slide 10 text
for scalable,
reliable systems
constantly provide service
with little or no downtime
Slide 11
Slide 11 text
Morden web apps are a
good fit, too
Slide 12
Slide 12 text
Erlang's
weakness
unfriendly syntax
not so shining tools
(compared to ruby)
Slide 13
Slide 13 text
Hello.Elixir
Slide 14
Slide 14 text
Elixir
created in 2012
by José Valim
was a member of
Rails core team
creator of Devise
Slide 15
Slide 15 text
Based on Erlang
compiled into Erlang VM codes
runs in Erlang VM (BEAM)
can use Erlang libararies
Slide 16
Slide 16 text
Ships with great tools
inspired by Ruby
mix (rake)
hex (gem & bundler)
iex (irb)
documentating
Slide 17
Slide 17 text
Ruby-like Syntax
IO.puts "Hello, world!"
Slide 18
Slide 18 text
Tuple
{:this, :is, 1, "tuple"}
Slide 19
Slide 19 text
List
list = [:this, "is", 1, "list"]
list ++ ["!"]
# => [:this, "is", 1, "list", "!"]
Slide 20
Slide 20 text
Keyword List
args = [{:timeout, 5000}, {:retry, false}]
# equals to
args = [timeout: 5000, retry: false]
# shortcut
# can be used as:
http(url, timeout: 5000, retry: false)
Pattern Matching
iex> {:ok, f} = File.read("./mix.exs")
# if read successfully
{:ok, "..."}
iex> {:ok, f} = File.read("NON_EXIST_FILE")
# oops
** (MatchError) no match of right hand side
value: {:error, :enoent}
Slide 31
Slide 31 text
Pattern Matching
result = do_something()
case result do
{:ok, result} -> process(result)
{:error, reason} -> show_msg(reason)
end
Slide 32
Slide 32 text
Pattern Matching
defmodule Fibonacci do
def fib(0), do: 0
def fib(1), do: 1
def fib(n) do
fib(n - 2) + fib(n - 1)
end
end
def fib(n) when n > 1 do
fib(n - 2) + fib(n - 1)
end
Slide 33
Slide 33 text
Pattern Matching
Suppose we are going to implement:
[1, 2, 4, 5, "hello", "world"]
[2, 1, 5, 4, "world", "hello"]
Slide 34
Slide 34 text
defmodule MyList do
def swap(list) do
_swap(list, [])
end
defp _swap([], current) do
current
end
defp _swap([a], current) do
current ++ [a]
end
defp _swap([a, b | tail], current) do
_swap(tail, current ++ [b, a])
end
end
Slide 35
Slide 35 text
Pattern Matching
defmodule UsersController do
def register(conn, %{"agreed" => false}) do
msg = "Please agree to continue."
render(conn, "new.html", alert: msg)
end
def register(conn, params) do
create_user_in_db(params)
redirect_to_profile(conn)
end
end
Logic branch
Logic trunk
Meta Programming
assert 1 == 2
1) test parse messages from ...
test/my_test.exs:5
Assertion with == failed
code: 1 == 2
lhs: 1
rhs: 2
Slide 43
Slide 43 text
Functional Programming
immutable data
pure functions
Slide 44
Slide 44 text
FP: same argument
= same result
Slide 45
Slide 45 text
class Employee
def initialize(name, salary)
@name = name
@salary = salary
end
def change_salary_by(amt)
@salary = @salary + amt
end
def description
"#{@name} makes #{@salary}"
end
end
bob = Employee.new("Bob", 10_000)
bob.change_salary(1000)
puts bob.description # "Bob makes 11000"
def change_salary_by(amt)
# make function pure by returning a new object
self.class.new(@name, @salary + amt)
end
bob = Employee.new("Bob", 10_000)
bob = bob.change_salary_by(1000)
FP way
Slide 46
Slide 46 text
Functional way with Elixir
defmodule Employee do
defstruct name: nil, salary: 0
def change_salary_by(person, amt) do
Map.update(person, :salary, amt, &(&1 + amt))
end
def description(person) do
"#{person.name} makes #{person.salary}"
end
end
%Employee{name: "Bob", salary: 10_000}
|> Employee.description()
|> Employee.change_salary_by(1000)
|> IO.puts # "Bob makes 11000"
Slide 47
Slide 47 text
“ Reuse your code without
worrying.
Slide 48
Slide 48 text
Process Process
1.spawn
2. wait (block)
2. send message
3. receive messages
Basic Concurrency in Elixir
Slide 49
Slide 49 text
Concurrency
defmodule SpawnExample do
def test do
spawn(Greet, :hello, [self, "Billy"])
receive do
{:ok, msg} -> IO.puts msg
end
end
end
Slide 50
Slide 50 text
Concurrency
defmodule Greet do
def hello(from, who) do
send(from, {:ok, "Hello, #{who}!"})
end
end
Paralleling
defmodule Pmap do
def map(collection, f) do
me = self
pids = collection
|> Enum.map(fn(element) ->
spawn_link(fn -> send(me, {self, f.(element)}) end)
end)
pids
|> Enum.map(fn(pid) ->
receive do
{^pid, result} -> result
end
end)
end
end
Slide 55
Slide 55 text
“ Processes share nothing.
Slide 56
Slide 56 text
“Processes everywhere,
services everywhere.
Slide 57
Slide 57 text
OTP -- toolset for massive
concurrent systems
(should be another topic)
Slide 58
Slide 58 text
(Some) Hard things in Ruby no
more exist in Elixir.
Slide 59
Slide 59 text
Elixir is so different
with but close to
Ruby.
Slide 60
Slide 60 text
Take it as your
next language
to learn
if not yet, ...
Slide 61
Slide 61 text
... and you will find
the same fun
when learning
Ruby.