Elixir

What we'll cover

  • General background
  • Language basics
  • Enjoyable language features (pipelines, pattern matching)
  • Intro to the BEAM (I'm still a noob)
  • Phoenix (mainly LiveView)
  • Downsides / pain points.

General Background

  • Made by José Valim (devise, rails core etc.)
  • Built on top of the Erlang VM (The BEAM)
  • Functional language
  • Immutable
  • Built for concurrency & uptime & fault tolerance
  • Whatsapp (erlang), Discord, Pinterest all built on top of it.

Quick concurrency demo

Language Fun

  • Just going to cover what I consider the fun parts!
  • Docs are really good if you want more
  • No doubt you'll want more by the end of this riveting talk.

Language Fun: Maps

  • Maps are the workhorse type
  • Used extensively for pattern matching
  • Keys & values can be anything you like

 

 

 

%{
  1 => 2,
  {"tuple"} => %{this: :that},
  ["even", "lists"] => ~r/regex/,
  :foo => <<?h, ?e, ?l, ?l, ?o>> 
}

Language Fun: Structs

  • Just a fancy layer over a map.

 

 

defmodule Car do
  @enforce_keys [:make]
  defstruct [:model, :make]
end

Language: Assignment & Pattern Matching

  • Probably the most awesome (and fun) part of Elixir.  You can match all the things in all the places.
  • Assignment is more like algebra (in that the two expressions on each side of the = are assumed to match eachother.  In elixir = is literally called the Match Operator

 

Language: Assignment & Pattern Matching

a = ["foo", %{bar: %{baz: "wibble"}}, [1, 2, 3, 4]]

[_, %{bar: %{baz: value}}, [1 | tail]] = a

Language: Functions (match arity & shape)

In Elixir, functions are uniquely identified by name and arity. Within a given name/arity, you can define multiple function heads that use pattern matching and guards. At call time, Elixir picks the right clause by trying the heads in order until one matches the arguments’ shape.

def foo(), do: "empty"
def foo(a) when is_number(a) do
  "you chose #{n}"
end
def foo(%{env: :prod} = _state, blah), do: "..."
def foo([]), do: "..."
def foo([h | t]), do: something_recursive
def foo(%User{} = user) # here we match a struct

Language: Can reduce* use of conditionals

Language: Pipeline Operator |>

defmodule Cleaner do
  def clean_text(text) do
    text
    |> String.trim()                              
    |> String.downcase()                     
    |> String.replace(~r/[^a-z0-9\s]/, "")       
    |> String.split(~r/\s+/, trim: true)          
    |> Enum.uniq()                              
    |> Enum.sort()                             
  end
end

vs

Enum.sort(
  Enum.uniq(
    String.split(
      String.replace(
        String.downcase(
          String.trim("  Hello, HELLO... World!! World  ")
        ),
        ~r/[^a-z0-9\s]/,
        ""
      ),
      ~r/\s+/,
      trim: true
    )
  )
)

Language: Misc

  • no early return (well, no return keyword)
  • in place mutations (x +=1) not allowed.
  • lists are "linked lists", arbitrary index means traversing the list (use a map instead)
  • mutating large structures means you get a new large structure* 

The BEAM

  1. Where the magic happens.
  2. Paralellizes the programs
  3. Takes care of process isolation
  4. Takes care of distribution
  5. Takes care of responsiveness
  6. Process communication (message passing)

Bogdan/Björn's Erlang Abstract Machine

BEAM demo

  1. Sasa Juric's server!
  2. Start some processes
  3. Move them around*
  4. See some CPU cores light up.
  5. See how cpu intensive tasks don't block the system
  6. Play with the dashboard and observer() tooling

Other things

  1. Processes can be linked
  2. Processes can be monitored
  3. Supervisors can restart processes (you can have entire supervision trees)
  4. Obervability of the running system (see live dashboard and :observer.start()

Phoenix

  1. The "rails" of the elixir world.
  2. Can have regular "RESTful" controllers etc.
  3. Also "liveview" which is what we'll have a play with here.
     

LiveView

  • The browser renders HTML sent from the server.

  • User interactions (clicks, form changes, etc.) send events over a persistent WebSocket connection to the server.

  • The server updates the state, re-renders the relevant HTML diff, and pushes only those changes back to the browser.

LiveView - Counter

Downsides of Elixir

  1. Fewer devs with experience, you may need to train up.
  2. Ecosystem 80K erlang repo vs 331K ruby...)
  3. Latency for liveview is a killer / requires thinking about.

Thanks! - Questions?

Language Basics: Tuples

  • Ordered collection of values

 

 

 

 

  • Often used in pattern matching / pipelining- and assume happy path. e.g.

     
{1, 2, 3}
{:ok, "something"}
{:error, "some error message"}
{:can, 1, ["contain"], AnythingYouLike}

Language Basics: Keyword Lists

  • Keyword lists are how you pass options around

 

 

  • (it gets converted to a list of two-value tuples}
  • Can have duplicated items (it's really just a list of tuples)
[this: "that", foo: "bar"] => [{:this, "that"}, {:foo, "bar"}]

Language Basics: Lists

  • Not like ruby.  Immutuable structures so can be expensive if you mutate a lot.
  • More like a linked list - prepend O(1) rather than append O(n)
  • Random access not easy, you must traverse the list.
  • Extracting the "head" and "tail" of a list & using recursion is normal.

Language: Recursion (tail call optimized)

Language: Scoping

Language Basics: Binaries

  • Access data as a sequence of bits & bytes
  • Unlikely to use them directly (to begin with), but, it is what strings are represented as
  • Can do pattern matching into it (think IOT stuff)

Elixir - An Introduction

By Patrick Davey

Elixir - An Introduction

  • 13