Intro to Elixir

Ciarán Walsh

Elixir is:

  • Functional…
  • But not ugly!
  • Immutable data, but re-usable variable names
  • Meta-Programming aware
  • Built on top of the Erlang VM
  • Exposes Erlang’s systems for robust, concurrent applications

Let’s start with…

Data Types

  • Unicode support for strings
  • Atoms
    :foobar
  • (Linked) lists
    [1, 2, 3]
  • Tuples
    {1, :foo, "Bar"}
  • Maps
    %{"foo" => :bar}

Modules and Functions

Functions must be in a module

Modules cannot be reopened


defmodule Foo do
  def foo(args) do
    :result
  end
end
					

Pipes


foo(bar(baz("qux")))
					

"qux" |> baz |> bar |> foo
					

foo(bar("qux", 2))

"qux" |> bar(2) |> foo
					

Pattern Matching

Looks like assignment:

result = {:ok, 123124}
						
BUT WAIT

{:ok, result} = {:ok, 123124}
						

Example Usage

File.open

returns a two element tuple

either:
{:ok, handle}
or:
{:error, reason}
So:
{:ok, handle} = File.open("thisfiledoesntexist")
** (MatchError) no match of right hand side value: {:error, :enoent}

Case statements


 case File.open("saljdaslkdjas") do
   {:ok, handle} ->
     # Code using `handle`

   {:error, reason} ->
     # Code using `reason`
 end
						

Underscores

  • Used to ignore results or function arguments
  • Cannot be read from

  {:ok, _} = File.copy(src, dest)

  {:ok, _bytes_copied} = File.copy(src, dest)
					

Functions + Pattern Matching =

defmodule HelloWorld do
  def hi("Ciarán") do
    "Hi there!"
  end

  def hi(name) do
    "Go away, #{name}!"
  end
end

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

		head # => 1

		tail # => [2, 3, 4, 5]

Recursion

defmodule SumList do
  def sum_list([head | tail], accumulator) do
    sum_list(tail, head + accumulator)
  end

  def sum_list([], accumulator) do
    accumulator
  end
end

SumList.sum_list([1, 2, 3, 4, 5], 0) # => 15
def sum_list(list, accumulator)
  if list == []
    return accumulator
  else
    head, *tail = list
    sum_list(tail, head + accumulator)
  end
end

sum_list([1, 2, 3, 4, 5], 0) # => 15