Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What Can We (Rubyists) Learn From Elixir

qhwa
September 23, 2016

What Can We (Rubyists) Learn From Elixir

A brief introduction to Elixir for Rubyists.

qhwa

September 23, 2016
Tweet

More Decks by qhwa

Other Decks in Programming

Transcript

  1. About Me work in web industry since 2004 built web

    products with Ruby since 2011 use Elixir since 2016
  2. I ❤ Ruby program happily high productivity easy to transform

    minds to codes high maintainability easy to write expressive and clean codes amazing community
  3. Elixir created in 2012 by José Valim was a member

    of Rails core team creator of Devise
  4. Based on Erlang compiled into Erlang VM codes runs in

    Erlang VM (BEAM) can use Erlang libararies
  5. Ships with great tools inspired by Ruby mix (rake) hex

    (gem & bundler) iex (irb) documentating
  6. List list = [:this, "is", 1, "list"] list ++ ["!"]

    # => [:this, "is", 1, "list", "!"]
  7. 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)
  8. Module defmodule Greet do def welcome do "Welcome to RubyConfChina!"

    end end Greet.welcome # or Greet.welcome() #=> "Welcome to RubyConfChina!"
  9. Pattern Matching iex> a = 1 1 iex> a 1

    iex> 1 = a 1 iex> 2 = a ** (MatchError) no match of right hand side value: 1
  10. Pattern Matching iex> 1 = 1 1 iex> 2 =

    1 ** (MatchError) no match of right hand side value: 1
  11. Pattern Matching iex> [1, 2, funny | tail] = [1,

    2, 3, 4, 5] [1, 2, 3, 4, 5] iex> funny 3 iex> tail [4, 5]
  12. 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}
  13. Pattern Matching result = do_something() case result do {:ok, result}

    -> process(result) {:error, reason} -> show_msg(reason) end
  14. 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
  15. Pattern Matching Suppose we are going to implement: [1, 2,

    4, 5, "hello", "world"] [2, 1, 5, 4, "world", "hello"]
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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"
  21. Process Process 1.spawn 2. wait (block) 2. send message 3.

    receive messages Basic Concurrency in Elixir
  22. Concurrency defmodule SpawnExample do def test do spawn(Greet, :hello, [self,

    "Billy"]) receive do {:ok, msg} -> IO.puts msg end end end
  23. Process Process 1.spawn 2. wait (block) 2. send message 3.

    receive messages Basic Concurrency in Elixir (Again)
  24. Paralleling [1, 2, 3, 4] |> Enum.map(&(&1 * &1)) #=>

    [1, 4, 9, 16] # parallel mapping! [1, 2, 3, 4] |> Pmap.map(&(&1 * &1)) #=> [1, 4, 9, 16]
  25. 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
  26. Q/A