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

Elixir Fundamentals

Elixir Fundamentals

Elixir Fundamentals for Elixir beginners

Avatar for Brian Zambrano

Brian Zambrano

December 07, 2016
Tweet

More Decks by Brian Zambrano

Other Decks in Programming

Transcript

  1. 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
  2. What we'll cover • Elixir as a functional language •

    Data types • Pattern matching • Runtime/processes
  3. 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
  4. 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)
  5. 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
  6. $ ls | > grep "\.exs" | > grep -v

    _test We already think functionally
  7. a = [1, 2, 3] func(a) a == [1, 2,

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

    has been re-bound # to a new list Rebinding isn't mutation
  9. 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
  10. 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
  11. 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]
  12. 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
  13. iex(5)> a = 1 1 iex(6)> 1 = 1 1

    iex(7)> 1 = a 1 merely matching up the left and right side of "="
  14. 1 = a doesn't work in other languages >>> a

    = 1 >>> 1 = a File "<stdin>", line 1 SyntaxError: can't assign to literal >>> 1 = 1 File "<stdin>", 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 `<main>' 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 `<main>'
  15. 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
  16. 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
  17. 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
  18. iex(14)> list = [1, 2, 3] [1, 2, 3] iex(15)>

    [1, _, b] = list [1, 2, 3] Ignoring during matching
  19. iex(2)> me = %{ name: "Brian", age: 43 } %{age:

    43, name: "Brian"} iex(3)> %{name: aname} = me %{age: 43, name: "Brian"} iex(6)> aname "Brian"
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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: <snip> 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
  26. 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
  27. 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
  28. 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