Pro Yearly is on sale from $80 to $50! »

Sweet Elixir - Short

Sweet Elixir - Short

Around 60% of telecom passes through Erlang. Facebook uses it and RabbitMQ is built on it. It’s fast, concurrent, distributed, but its Prolog-inspired syntax leaves much to be desired. Ruby is beautiful and powerful, but struggles at scale and treats concurrency as a second class citizen. Elixir - a young, functional, meta programming language - aims to resolve this mighty conflict by providing a rosy syntax inspired by Ruby that compiles to Erlang VM compatible bytecode.
Together we’ll take a guided tour of Elixir basics and functional programming concepts like pattern matching, pipelines and tail-call recursion. From there we’ll explore the distributed and concurrent nature of Elixir, the fault tolerant features of OTP, and ways you can leverage Elixir in your existing architectures today.

Whether you roll with a Mac, Windows or Linux everyone will leave an Elixir programmer.

32de0bd2ba869609d26fd052a4622778?s=128

Ryan Cromwell

May 31, 2014
Tweet

Transcript

  1. Ryan Cromwell Sweet Elixir!

  2. Pipeline What’s Elixir? |> Types, Functions, Modules |> Pattern Matching

    |> Maps, Structs, & Protocols |> Pipelines |> Processes |> OTP, Phoenix
  3. Sweet Elixir! What’s Elixir?

  4. Functional

  5. Erlang VM

  6. Concurrent

  7. Distributed

  8. Sweet Elixir! Setup

  9. Mac #Mac! $> brew update! $> brew install erlang! $>

    brew install elixir! ! #Linux! <Your package manager here>! ! #Windows! PS> cinst elixir
  10. SWEET ELIXIR! SECTION TITLE

  11. $> iex ! iex(1)> IO.puts “hello world!”

  12. $> elixir hello_world.exs hello world

  13. elixirc hello_world.ex ! $> ls Elixir.HelloWorld.beam

  14. $> mix deps.get $> mix compile $> mix phoenix.start

  15. hex.pm

  16. Sweet Elixir! Types

  17. is_number 1 ! ! ! ! ! ! ! !

    ! ! ! ! ! #=> true! ! is_integer 1! ! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_number 2.1! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_float 2.1! ! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_integer 2.1! ! ! ! ! ! ! ! ! ! ! ! #=> false
  18. 1 == 1.0!! ! ! ! ! ! ! !

    ! ! ! ! ! ! #=> true! ! 1 === 1.0! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> false
  19. is_boolean true! ! ! ! ! ! ! ! !

    ! ! #=> true! ! true or false! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! true || false! ! ! ! ! ! ! ! ! ! ! ! #=> true
  20. is_atom :selfConf!! ! ! ! ! ! ! ! !

    #=> true! ! is_atom true! ! ! ! ! ! ! ! ! ! ! ! ! #=> true
  21. is_list [1,2,3]! ! ! ! ! ! ! ! !

    ! ! #=> true! ! length [1,2,3]! ! ! ! ! ! ! ! ! ! ! ! #=> 3! ! [1,2] ++ [3,4]! ! ! ! ! ! ! ! ! ! ! ! #=> [1,2,3,4]! ! iex> h Enum! ! iex> h Stream
  22. is_tuple {1, “b”, :c}! ! ! ! ! ! !

    ! #=> true! ! elem! {1, “b”, :c}, 1!! ! ! ! ! ! ! #=> “b”! ! t = {1, “b”, :c}! set_elem t, 2, :d!! ! ! ! ! ! ! ! ! #=> {1, “b”, :d}! ! Integer.parse “1.0a3”!! ! ! ! ! ! ! #=> {1, “.0a3”}
  23. is_list ‘hello’! ! ! ! ! ! ! ! !

    ! ! #=> true! ! is_list “hello”! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_binary “hello”!! ! ! ! ! ! ! ! ! #=> true
  24. “hello” <> “ world”! ! ! ! ! ! !

    ! ! ! #=> “hello world”! ! who = “ryan”! “hello #{who}”! ! ! ! ! ! ! ! ! ! ! ! ! #=> “hello ryan”
  25. SWEET ELIXIR! Anonymous Functions

  26. add = fn (x, y) -> x + y end!

    ! add.(2,2)! ! ! ! ! ! ! ! ! ! ! #=> 4
  27. do_calc = fn(x,y, calc) -> calc.(x,y) end! ! do_calc.(2,3, add)!

    ! ! ! ! ! ! ! ! #=> 5! ! do_calc.(2,4, &(&1 * &2))! ! ! ! ! #=> 8
  28. SWEET ELIXIR! Modules

  29. defmodule Weather do! ! def celsius_to_fahrenheit(celsius) do! ! ! (celsius

    * 1.8) + 32! ! end! ! ! def boiling, do: 100! ! def freezing, do: 0! end! ! Weather.celsius_to_fahrenheit(20) ! ! #=> 68.0
  30. import alias defmodule USWeather do! ! import Weather, only: [freezing:

    0,! ! ! ! celsius_to_fahrenheit: 1]! ! ! alias :math, as Math! ! ! def cold_in_michigan do! ! ! celsius_to_fahrenheit(freezing - 10)! ! end! end
  31. SWEET ELIXIR! Pattern Matching

  32. [head | tail] = [1,2,3,4,5]! ! head! ! ! !

    ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> 1! ! tail! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> [2,3,4,5]
  33. {a,b,c}! = {1,”b”,:c}! ! a!! ! ! ! ! !

    ! ! ! ! ! ! ! ! ! ! ! ! ! #=> 1! ! b!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> “b”! ! c!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> :c
  34. {a,b,:other}!= {1,”b”,:c}

  35. {a,b,:other}!= {1,”b”,:c}! ! ** (MatchError) no match of right hand

    side value: {1, "b", :c}
  36. Control Flow calculate = fn expression ->! case expression do!

    {:+, num1, num2} -> num1 + num2! {:-, num1, num2} -> num1 - num2! {:*, num1, 0} -> 0! {:*, num1, num2} -> num1 * num2! end! end
  37. defmodule Countdown do! def run(from, to) when from >= to

    do! run(from, to, from)! end! ! def run(_from, to, current) when to == current do! IO.puts to! IO.puts "Done!"! end! ! def run(from, to, current) do! IO.puts current! run(from, to, current - 1)! end! end Function
  38. defmodule PersonPrefixer do! def prefix(p = %{ gender: :male }),

    do: "Mr."! def prefix(p = %{ gender: :female }), do: "Mrs."! def prefix(p), do: ""! end! ! PersonPrefixer.prefix %{first: “Sandy”, gender: :female} #=> “Mrs”
  39. SWEET ELIXIR! Maps Structs Protocols

  40. Maps speaker = %{! first: “Ryan”,! last: “Cromwell”,! twitter: “@cromwellryan”,!

    “home town” => “Dayton, OH”! }! ! speaker[:twitter] #=> “@cromwellryan”! ! speaker[“Home Town”] #=> “Dayton, OH”
  41. Structs defmodule Kid do! ! defstruct name: "ryan", age: 7!

    end
  42. Protocols defprotocol Good do! @doc "Returns true if data is

    considered good"! def good?(data)! end
  43. Ad-hoc Polymorphism defimpl Good, for: Kid do! ! def good?(%Kid{name:

    "Ryan"}), do: true! ! def good?(_), do: false! end! ! Good.good? %Kid{name: "Ryan"}! ! ! ! ! ! ! ! #> true! Good.good? %Kid{name: "Ben"}!! ! ! ! ! ! ! ! #> false
  44. SWEET ELIXIR! Pipelines

  45. Enum.map [1,2,3,4], fn (x) -> x * 2 !! !

    ! ! ! #=> [2,4,6,8]! ! [1,2,3,4] |> Enum.map(fn (x) -> x *2)! ! ! ! ! #=> [2,4,6,8]
  46. lines = String.split file_content, "\n"! lines = Stream.filter lines, &(String.length(&1)

    > 0)! lengths = Stream.map lines, &(String.split &1)! triangles = Stream.map lengths, &(list_to_tuple &1)! classifications = Stream.map triangles, &( %{sides: &1, classification: Classifier.classify &1} )! ! messages = Stream.map classifications, &( "Triangle #{inspect &1[:sides]} is #{&1[:classification]}" )! result = Enum.join(messages, "\n")! ! IO.puts result before
  47. file_content! |> String.split("\n")! |> Stream.filter( &(String.length(&1) > 0) )! |>

    Stream.map( &(String.split &1) )! |> Stream.map( &(list_to_tuple &1) )! |> Stream.map( &(%{sides: &1, class: Classifier.classify &1}) )! |> Stream.map( &("Triangle #{inspect &1[:sides]} is #{&1[:class]}") )! |> Enum.join("\n")! |> IO.puts! after
  48. SWEET ELIXIR! Processes

  49. Process Process Process

  50. pid = spawn fn ->! receive do! {sender, :ping} ->!

    IO.puts "Got ping"! send sender, :pong! end! end
  51. Live Coding

  52. SWEET ELIXIR! OTP

  53. ‣ Supervisor ‣ GenServer ‣ GenFSM ‣ GenEvent ‣ Application

  54. None
  55. SWEET ELIXIR! phoenix

  56. github.com/phoenixframework/phoenix

  57. $> mix phoenix.new your_app /path/to/scaffold/your_app! ! $> mix do deps.get,

    compile! ! $> mix phoenix.start
  58. Inspired by Rails defmodule ChatDemoEx.Router do! use Phoenix.Router! use Phoenix.Router.Socket,

    mount: "/ws"! ! plug Plug.Static, at: "/static", from: :chat_demo_ex! get "/", ChatDemoEx.Controllers.Pages, :index, as: :page! ! channel "rooms", Chat.Channels.Rooms! end
  59. defmodule Chat.Channels.Rooms do! use Phoenix.Channel! ! def event(socket, "new:message", message)

    do! broadcast socket, "new:message", message! ! socket! end! end Elixir
  60. Javascript chan.send("new:message", {! ! username: “cromwellryan”, ! ! body: “hello

    internets!”! });! !
  61. SWEET ELIXIR! LEARN YOU SOME ELIXIR

  62. Resources ‣ elixir-lang.org ‣ elixirsips.com ‣ elixirconf.com (July 25-26) !

    ‣ PragProg: Programming Elixir ! ‣ github.com/cromwellryan/sweetelixir ‣ http://bit.ly/sweetelixir-short
  63. THANKS! @cromwellryan ryan@heysparkbox.com