An introduction to

@sbfrr

 

le Wagon alumni batch #2

Running on the BEAM

  • scalable
  • fault-tolerant 
  • distributed
  • non-stop

Inspired from Ruby 

defmodule Math do
  def sum(a, b) do
      a + b
  end
end



class Math
  def sum(a, b)
      a + B
  end
end

What's going to happen ?

  • iex == pry
  • pair programming
  • learning by doing

 

 

http://elixir-lang.org/docs/stable/elixir/Kernel.html

and h is your friend inside of iex ;)

How to deal with the compiler ?

First option

>  iex
>  c("my_elixir_file.ex")
>  MyModule.my_function()


Second option

> elixir "my_elixir_file.ex"


Need HELP ?

> h Module
> h Module.function
> h Module.function/arity

Try it yourself ! It's fun !

LANGUAGE PRIMITIVES

Data Types

  • Integer => 1
  • Float => 1.0
  • Atom => :atom
  • Booleans => true / false
  • List => [1, 2, 3]
  • Tuple => {1, 2, 3}
  • String => "string"
  • Function => fn() -> "hello" end
  • Keyword List => [a: "a"] == [{:a, "a"}]

Assignment

# Reassignment

a = 1   # 1
a = 2   # 2


# Underscore Variable

_ = Do.something("with", "this")


# Assignment and Mathematical Equal

a = [1, 2]    # [1, 2]

[1, 2] = a    # [1, 2]


[2, 3] = a    # ???? Try it ! It's fun as well ;)


# What about that ?

[1, a] = [2, 3]

# And that ?

[a|_] = [1, 2]

Tuples or Lists ?


# Lists

iex> [head|tail] = [1, 2, 3]
[1, 2, 3]

iex> 1 = head
1

iex> [2, 3] = tail
[2, 3]

iex> list = [1 | [2 | [3 | []]]]
[1, 2, 3]

iex> [0 | list]
[0, 1, 2, 3]



# Tuples

iex> tuple = {:ok, "hello"}
{:ok, "hello"}

iex> elem(tuple, 1)
"hello"

Pattern Matching

iex> 1 = x
1
iex> 2 = x
** (MatchError) no match of right hand side value: 1


iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}

iex> a
:hello

iex> b
"world"

iex> {a, b, c} = {:hello, "world"}
** (MatchError) no match of right hand side value: {:hello, "world"}

Module and Functions

defmodule BasicMath do

  def add(x, y) do
    x + y
  end

  def add_square(x, y) do
    square(x) + square(y)
  end

  defp square(x) do
    x * x
  end

end

BasicMath.add_square(2,2) # 8

Functions and Pattern Matching

defmodule Say do

    
  def hello("world") do
    "No way, I can't say hello world anymore!" 
  end

  def hello(name) do
    "Hello " <> name
  end

end

Say.hello("world") #"No way, I can't say hello world anymore!"
Say.hello("John Doe") #"Hello John Doe"

In Case of...

defmodule Say do

  def hello(name) do
    case name do
      "world" ->
        "No way, I can't say hello world anymore!"
       _ ->
        "Hello " <> name
    end
  end

end

Say.hello("world") #"No way, I can't say hello world anymore!"
Say.hello("John Doe") #"Hello John Doe"

Pattern Loop Matching

defmodule LoopOver do

    
  def this_list([]), do: IO.puts "DONE"
  def this_list([head|tail]) do
    IO.puts head
    this_list(tail)
  end

end

LoopOver.this_list([1, 2, 3])

YOUR TURN !!!

WRITE AN IMPLEMENTATION OF THE FIBONACCI SERIES IN ELIXIR 

 

GO GO GO !!!

A (NAIVE) IMPLEMENTATION

#saved as test_module.ex

defmodule TestModule do

  def fib(0), do: 0
  def fib(1), do: 1

  def fib(n), do: fib(n-1) + fib(n-2)
end

####  Uses in iex

# TestModule.fib(0) #=> 0
# TestModule.fib(1) #=> 1
# TestModule.fib(10) #=> 55
# TestModule.fib(-10) #=> this will hang as it will recurse for infinite time

Object vs. Process

Let's get into the real shit !

Remember

First option

>  iex
>  c("my_elixir_file.ex")
>  MyModule.my_function()


Second option

> elixir "my_elixir_file.ex"

Third option

> iex -r "my/file/path.ex"


Need HELP ?

> h Module
> h Module.function
> h Module.function/arity

Elixir uses the actor model of concurrency.

 

An actor is an independent process that shares nothing with any other process.

 

You can spawn new processes, send them messages, and receive messages back.

 

And that’s it  (apart from some details about error handling and monitoring).

from "Programming Elixir"

What is a process ?

iex> pid = spawn fn -> 1 + 2 end
#PID<0.44.0>

iex> Process.alive?(pid)
false

iex> self()

iex> Process.alive?(self())


# Let's take the opportunity to introduce the pipe operator

iex> self() |> Process.alive? 

Sending and receiving messages

iex> self |> send({:hello, "world"})
{:hello, "world"}

iex> receive do
...>   {:hello, msg} -> msg
...> end

"world"

Let's CODE !!!

Pattern matching and messages

iex> send self(), {:hello, "world"}
{:hello, "world"}

iex> receive do
...>   {:hello, msg} -> msg
...>   {:world, msg} -> "won't match"
...> end

"world"

Let's CODE !!

Links

 

iex> spawn fn -> raise "oops" end
#PID<0.58.0>


iex> spawn_link fn -> raise "oops" end
#PID<0.41.0>

Let's CODE !!

 

A Key/Value Store

 

defmodule KV do
  def start_link do
    Task.start_link(fn -> loop(%{}) end)
  end

  defp loop(map) do
    receive do
      {:get, key, caller} ->
        send caller, Map.get(map, key)
        loop(map)
      {:put, key, value} ->
        loop(Map.put(map, key, value))
    end
  end
end

Naming a Process

 


iex(2)> Process.register(pid, Project.Worker)
true


iex(3)> pid = Process.whereis(Project.Worker)
#PID<0.93.0>

Your turn

 

What about two process playing PING/PONG ?

 

Can you code it ?

Inspired by

  • http://elixir-lang.org/getting-started/introduction.html

 

  • http://blog.songsaboutsnow.com

 

  • Programming Elixir Book

Would you like some more ?

OTP ? PHOENIX ? 

Just name it ;)

THANKS

@sbfrr

 

le Wagon alumni batch #2