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

Elixir Fundamentals

Elixir Fundamentals

Elixir Fundamentals for Elixir beginners

Brian Zambrano

December 07, 2016
Tweet

More Decks by Brian Zambrano

Other Decks in Programming

Transcript

  1. Elixir Fundamentals
    (for Elixir beginners)
    Brian Zambrano
    Boulder Elixir Meetup
    December 6, 2016

    View Slide

  2. Me
    • Originally from SF Bay Area
    • Writing Python since 2001
    • Mostly backend systems +
    SAAS architecture +
    (micro)services
    • Plenty of Django
    • Plenty of horrible codebases
    • Looking for a better way

    View Slide

  3. What we'll cover
    • Elixir as a functional language
    • Data types
    • Pattern matching
    • Runtime/processes

    View Slide

  4. Why Elixir?
    • Scalability / concurrency
    • Distributed system / microservices usually requires tooling, systems and
    lots of management
    • Distributed programming built into the language via Erlang/BEAM
    • Performance
    • Many languages aren't that good at resource utilization: Python, Ruby,
    JavaScript/Node
    • Other more performant languages are a bit too low-level: C, Go, Rust
    • Functional
    • Immutable state means concurrency is easier
    • Immutable state means is harder to write big balls of mud

    View Slide

  5. Procedural or OO
    1 def calculate_taxes(username, year=2016):
    2 try:
    3 person = PeopleService(username)
    4 except PeopleService.NotFoudException:
    5 raise e
    6
    7 orders = OrdersService.get_orders_for_customer(person)
    8 if not orders:
    9 return
    10
    11 tax = calculate_sales_tax(orders, year)
    12
    13 return prepare_filing(tax)

    View Slide

  6. vs. Functional
    1 defmodule TaxService do
    2
    3 def calculate_taxes(username, year // 2016) do
    4 {:ok, person} = PeopleService(username)
    5
    6 person
    7 |> OrderService.for_customer
    8 |> calculate_taxes(year)
    9 |> prepare_filing
    10 end
    11
    12 end

    View Slide

  7. $ ls |
    > grep "\.exs" |
    > grep -v _test
    We already think
    functionally

    View Slide

  8. a = [1, 2, 3]
    func(a)
    # what is a?
    Removing mutation

    View Slide

  9. a = [1, 2, 3]
    func(a)
    a == [1, 2, 3]
    true # always
    In Elixir a won't change

    View Slide

  10. a = [1, 2, 3]
    a = func(a)
    # a has been re-bound
    # to a new list
    Rebinding isn't mutation

    View Slide

  11. Elixir types
    1, 100_000,
    0xDEADBEEF, 0b10111
    Integer
    1.0, 0.31415e1, 31415.0e-5 Float
    :ok, :is_binary?, :srsly! Atom
    1..10 Ranges
    ~r/[aeiou]/, ~r{[aeiou]} RegEx
    {:ok, file}, {:error, _} Tuple
    [1, 2, 3], ['a', 'b'] List
    %{ name: "bz", state: "CO" }
    %{ "CO" => "Colorado" }
    Map
    true, false, nil Truth
    <<1 :: size(4), 15 :: size(4)>> #
    0001 1111
    Binaries

    View Slide

  12. Elixir Strings
    • Single quoted
    • List of integers
    • iex represents this as a string if each char is
    printable
    • Double quoted
    • Sequence of UTF-8 bytes
    • Each byte is a binary

    View Slide

  13. Char lists
    iex(102)> [67, 97, 116]
    'Cat'
    iex(103)> is_list 'hello world'
    true
    iex(104)> List.to_tuple 'Cat'
    {67, 97, 116}
    iex(107)> 'CaӠ'
    [67, 97, 19971]

    View Slide

  14. Strings
    iex(128)> "C" == 'C'
    false
    iex(135)> [67]
    'C'
    iex(136)> "C" == << 67 :: size(8) >>
    true
    iex(138)> String.upcase("cat")
    "CAT"
    iex(146)> String.length("CaӠ")
    3
    iex(147)> byte_size("CaӠ")
    5

    View Slide

  15. Pattern
    matching

    View Slide

  16. Pattern matching vs
    variable assignment

    View Slide

  17. iex(5)> a = 1
    1
    iex(6)> 1 = 1
    1
    iex(7)> 1 = a
    1
    merely matching
    up the left and
    right side of "="

    View Slide

  18. 1 = a doesn't
    work in other
    languages
    >>> a = 1
    >>> 1 = a
    File "", line 1
    SyntaxError: can't assign to literal
    >>> 1 = 1
    File "", line 1
    SyntaxError: can't assign to literal
    >>>
    irb(main):001:0> a = 1
    => 1
    irb(main):002:0> 1 = a
    SyntaxError: (irb):2: syntax error,
    unexpected '=', expecting end-of-input
    1 = a
    ^
    from /usr/local/bin/irb:11:in `'
    irb(main):003:0> 1 = 1
    SyntaxError: (irb):3: syntax error,
    unexpected '=', expecting end-of-input
    1 = 1
    ^
    from /usr/local/bin/irb:11:in `'

    View Slide

  19. 1 = a cannot work in Elixir too!
    a must be defined before
    matching
    iex(1)> 1 = a
    ** (CompileError) iex:1: undefined function a/0
    iex(1)> a = 1
    1
    iex(2)> 1 = a
    1

    View Slide

  20. iex(8)> list = [1, 2, 3]
    [1, 2, 3]
    iex(9)> [a, 2, b] = list
    [1, 2, 3]
    iex(10)> a
    1
    iex(11)> b
    3
    Matching with lists

    View Slide

  21. iex(14)> list = [1, 2, 3]
    [1, 2, 3]
    iex(15)> [a, 1, b] = list
    ** (MatchError) no match of
    right hand side value: [1, 2, 3]
    Mis-matching with lists

    View Slide

  22. iex(14)> list = [1, 2, 3]
    [1, 2, 3]
    iex(15)> [1, _, b] = list
    [1, 2, 3]
    Ignoring during matching

    View Slide

  23. Pattern matching
    with Maps

    View Slide

  24. iex(2)> me = %{
    name: "Brian",
    age: 43
    }
    %{age: 43, name: "Brian"}
    iex(3)> %{name: aname} = me
    %{age: 43, name: "Brian"}
    iex(6)> aname
    "Brian"

    View Slide

  25. iex(7)> %{name: "Brian"} = me
    %{age: 43, name: "Brian"}
    iex(8)> %{name: "Joe"} = me
    ** (MatchError) no match of
    right hand side value: %{age:
    43, name: "Brian"}
    Mis-matching with maps

    View Slide

  26. Pattern matching
    in functions

    View Slide

  27. Matching based on
    function arguments
    1 defmodule Fib do
    2 def fib(1), do: 1
    3 def fib(2), do: 1
    4 def fib(n), do: fib(n-1) + fib(n-2)
    5 end

    View Slide

  28. Matching based on
    function arity
    1 defmodule Calculator do
    2
    3 def inc(n) do
    4 n + 1
    5 end
    6
    7 def inc(n, m) do
    8 n + m
    9 end
    10
    11 end

    View Slide

  29. Matching based on
    function arity
    iex(1)> Calculator.inc(5)
    6
    iex(2)> Calculator.inc(5, 5)
    10

    View Slide

  30. Processes and
    Supervisors

    View Slide

  31. Simple GenServer
    defmodule Calculator.Server do
    use GenServer
    # API
    def start_link do
    GenServer.start_link(__MODULE__, nil, name: :calculator)
    end
    def divide(n, m) do
    GenServer.call(:calculator, {:divide, n, m})
    end
    # end API

    View Slide

  32. Simple GenServer
    # Server callbacks
    def init(nil) do
    {:ok, nil}
    end
    def handle_call({:multiply, n, m}, _from, _state) do
    { :reply, n * m, nil }
    end
    end

    View Slide

  33. Running our Server
    iex(1)> Calculator.Server.start_link
    {:ok, #PID<0.119.0>}
    iex(2)> Calculator.Server.divide(10, 2)
    5.0
    iex(3)> Calculator.Server.divide(10, 0)
    ** (EXIT from #PID<0.117.0>) an exception was raised:

    State: nil
    nil
    iex(1)>
    iex(2)> Calculator.Server.divide(10, 2)
    ** (exit) exited in: GenServer.call(:calculator, {:divide, 10, 2}, 5000)
    ** (EXIT) no process
    (elixir) lib/gen_server.ex:596: GenServer.call/3

    View Slide

  34. Running with Supervisor
    1 defmodule Calculator.Supervisor do
    2 use Supervisor
    3
    4 def start_link do
    5 Supervisor.start_link(__MODULE__, [])
    6 end
    7
    8 def init(_) do
    9 children = [
    10 worker(Calculator.Server, [])
    11 ]
    12 supervise(children, strategy: :one_for_one)
    13 end
    14 end

    View Slide

  35. Running with Supervisor
    iex(1)> Calculator.Supervisor.start_link
    {:ok, #PID<0.108.0>}
    iex(2)> Calculator.divide(10, 2)
    5.0
    iex(3)> Calculator.divide(10, 0)
    ** (RuntimeError) Cannot divide by zero
    (calculator) lib/calculator.ex:6: Calculator.divide/2
    iex(3)> Calculator.divide(10, 2)
    5.0

    View Slide

  36. Resources
    Introduction to Elixir & Phoenix
    https://youtu.be/cKeJJldQRgI
    GenServer/Supervisor gists
    https://git.io/calculator
    https://git.io/supervisor
    Programming Elixir
    https://pragprog.com/book/elixir/programming-elixir
    Docs
    https://elixirschool.com
    http://elixir-lang.org/getting-started/introduction.html

    View Slide