SlideShare a Scribd company logo
1 of 85
Download to read offline
Elixir and Phoenix
fast, concurrent and explicit
Tobias Pfeiffer
@PragTob
pragtob.info
Elixir and Phoenix
fast, concurrent and explicit
Tobias Pfeiffer
@PragTob
pragtob.info
Platform
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Ruby-like Syntax
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
First-class functions
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Tail-Call Optimization
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Doctesting
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Piotr Szotkowski"}) do
IO.puts "Hi Piotr, awesome keyboards!"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Piotr Szotkowski"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Piotr Szotkowski"}) do
IO.puts "Hi Piotr, awesome keyboards!"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Piotr Szotkowski"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Piotr Szotkowski"}) do
IO.puts "Hi Piotr, awesome keyboards!"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Piotr Szotkowski"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Piotr Szotkowski"}) do
IO.puts "Hi Piotr, awesome keyboards!"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Piotr Szotkowski"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Piotr Szotkowski"}) do
IO.puts "Hi Piotr, awesome keyboards!"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Piotr Szotkowski"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmacro plug(plug, opts  []) do
quote do
@plugs {unquote(plug), unquote(opts), true}
end
end
Meta Programming
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defimpl Blank, for: Map do
def blank?(map), do: map_size(map) == 0
end
defimpl Blank, for: Atom do
def blank?(false), do: true
def blank?(nil), do: true
def blank?(_), do: false
end
Polymorphism
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defimpl Blank, for: Map do
def blank?(map), do: map_size(map) == 0
end
defimpl Blank, for: Atom do
def blank?(false), do: true
def blank?(nil), do: true
def blank?(_), do: false
end
Polymorphism
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defimpl Blank, for: Map do
def blank?(map), do: map_size(map) == 0
end
defimpl Blank, for: Atom do
def blank?(false), do: true
def blank?(nil), do: true
def blank?(_), do: false
end
Polymorphism
@spec all?(t) :: boolean
@spec all?(t, (element -> as_boolean(term))) :: boolean
def all?(enumerable, fun  fn(x) -> x end)
def all?(enumerable, fun) when is_list(enumerable) and
is_function(fun, 1) do
do_all?(enumerable, fun)
end
Implemented in itself!
@spec all?(t) :: boolean
@spec all?(t, (element -> as_boolean(term))) :: boolean
def all?(enumerable, fun  fn(x) -> x end)
def all?(enumerable, fun) when is_list(enumerable) and
is_function(fun, 1) do
do_all?(enumerable, fun)
end
Optional Type Annotations
defmodule Plug do
@type opts :: tuple | atom | integer | float | [opts]
@callback init(opts) :: opts
@callback call(Plug.Conn.t, opts) :: Plug.Conn.t
end
“Interfaces”
defmodule Plug do
@type opts :: tuple | atom | integer | float | [opts]
@callback init(opts) :: opts
@callback call(Plug.Conn.t, opts) :: Plug.Conn.t
end
“Interfaces”
defmodule Plug.Head do
@behaviour Plug
alias Plug.Conn
def init([]), do: []
def call(%Conn{method: "HEAD"} = conn, []) do
%{conn | method: "GET"}
end
def call(conn, []), do: conn
end
“Interfaces”
defmodule Plug.Head do
@behaviour Plug
alias Plug.Conn
def init([]), do: []
def call(%Conn{method: "HEAD"} = conn, []) do
%{conn | method: "GET"}
end
def call(conn, []), do: conn
end
“Interfaces”
Functional Programming?
2.2.2 :001 > [1, 2, 3, 4].map { |i| i + 1 }
=> [2, 3, 4, 5]
iex(2)> Enum.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
vs
Where to call functions
Transformation
of Data
Pipe
people = DB.find_customers
orders = Orders.for_customers(people)
tax = sales_tax(orders, 2013)
filing = prepare_filing(tax)
filing = DB.find_customers
|> Orders.for_customers
|> sales_tax(2013)
|> prepare_filing
Pipe
filing =
prepare_filing(sales_tax(
Orders.for_cusstomers(DB.find_customers), 2013))
Pipe
filing = DB.find_customers
|> Orders.for_customers
|> sales_tax(2013)
|> prepare_filing
Pipe
person = Person.new(attributes)
do_something(person)
insert_in_db(person)
Immutable Data
person = Person.new(attributes)
person = do_something(person)
insert_in_db(person)
Immutable Data
Principles vs Power
Minimize state
vs
Hiding state
Same Input,
Same Output
Testing++
Readability
First class actor support
OTP
Supervisors
Umbrella apps
connection
|> endpoint
|> router
|> pipelines
|> controller
|> model
|> view
Flow
scope "/", Rumbl do
pipe_through :browser
get "/", PageController, :index
resources "/users", UserController,
only: [:index, :show, :new, :create]
resources "/sessions", SessionController,
only: [:new, :create, :delete]
get "/watch/:id", WatchController, :show
end
Routes
scope "/", Rumbl do
pipe_through :browser
get "/", PageController, :index
resources "/users", UserController,
only: [:index, :show, :new, :create]
resources "/sessions", SessionController,
only: [:new, :create, :delete]
get "/watch/:id", WatchController, :show
end
Routes
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Rumbl.Auth, repo: Rumbl.Repo
end
pipeline :api do
plug :accepts, ["json"]
end
Pipelines
def new(conn, _params) do
changeset = User.new_changeset(%User{})
render conn, "new.html", changeset: changeset
end
Controller
defmodule Rumbl.User do
use Rumbl.Web, :model
schema "users" do
field :name, :string
field :username, :string
field :password, :string, virtual: true
field :password_hash, :string
has_many :videos, Rumbl.Video
timestamps
end
# ...
end
Model
defmodule Rumbl.UserView do
use Rumbl.Web, :view
alias Rumbl.User
def first_name(%{name: name}) do
name
|> String.split(" ")
|> Enum.at(0)
end
end
View
<%= form_for @changeset, user_path(@conn, :create), fn
form -> %>
<div class="form-group">
<%= text_input form, :name, placeholder: "Name",
class: "form-control" %>
<%= error_tag form, :name %>
</div>
<div class="form-group">
<%= text_input form, :username, placeholder:
"Username", class: "form-control" %>
<%= error_tag form, :username %>
</div>
<div class="form-group">
<%= password_input form, :password, placeholder:
"Password", class: "form-control" %>
<%= error_tag form, :password %>
</div>
<%= submit "Create User", class: "btn btn-primary" %>
<% end %>
Template
def new_changeset(model, params  %{}) do
model
|> cast(params, ~w(name username), [])
|> unique_constraint(:username)
|> validate_length(:username, min: 1, max: 20)
end
def registration_changeset(model, params) do
model
|> new_changeset(params)
|> cast(params, ~w(password), [])
|> validate_length(:password, min: 6, max: 100)
|> put_pass_hash()
end
Changesets
def new_changeset(model, params  %{}) do
model
|> cast(params, ~w(name username), [])
|> unique_constraint(:username)
|> validate_length(:username, min: 1, max: 20)
end
def registration_changeset(model, params) do
model
|> new_changeset(params)
|> cast(params, ~w(password), [])
|> validate_length(:password, min: 6, max: 100)
|> put_pass_hash()
end
Changesets
def new_changeset(model, params  %{}) do
model
|> cast(params, ~w(name username), [])
|> unique_constraint(:username)
|> validate_length(:username, min: 1, max: 20)
end
def registration_changeset(model, params) do
model
|> new_changeset(params)
|> cast(params, ~w(password), [])
|> validate_length(:password, min: 6, max: 100)
|> put_pass_hash()
end
Changesets
def create(conn, %{"user" => user_params}) do
changeset = User.registration_changeset(%User{}, user_params)
case Repo.insert changeset do
{:ok, user} ->
conn
|> Rumbl.Auth.login(user)
|> put_flash(:info, "You successfully registered!")
|> redirect(to: user_path(conn, :index))
{:error, changeset}->
render conn, "new.html", changeset: changeset
end
end
Changesets
defmodule Rumbl.VideoChannel do
use Rumbl.Web, :channel
def join("videos:" <> video_id, _params, socket) do
{:ok, socket}
end
def handle_in("new_annotation", params, socket) do
broadcast! socket, "new_annotation", %{
user: %{username: "anon"},
body: params["body"],
at: params["at"]
}
{:reply, :ok, socket}
end
end
Channels
The right tool
iex(13)> user = Repo.get_by(User, name: "Homer")
iex(14)> user.videos
#Ecto.Association.NotLoaded<association :videos is not
loaded>
Explicit preloading
iex(13)> user = Repo.get_by(User, name: "Homer")
iex(14)> user.videos
#Ecto.Association.NotLoaded<association :videos is not
loaded>
Explicit preloading
iex(15)> Repo.preload(user, :videos)
iex(16)> user.videos
#Ecto.Association.NotLoaded<association :videos is not
loaded>
Explicit preloading
iex(17)> user = Repo.preload(user, :videos)
iex(18)> user.videos
[%Rumbl.Video{__meta__: #Ecto.Schema.Metadata<:loaded>,
category: #Ecto.Association.NotLoaded<association
:category is not loaded>,
category_id: nil, description: "such great many wow", id:
3,
inserted_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, title:
"Hubidubiee",
updated_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, url:
"www.lol.com",
user: #Ecto.Association.NotLoaded<association :user is
not loaded>,
user_id: 5}]
Explicit preloading
So we all go and do Elixir
and Phoenix now?
❤
Dirtiness
Baggage
Eco-System
A new land
So, would you start a
new project in Elixir and
Phoenix now?
Q&A question #1
IT 
DEPENDS
IT 
DEPENDS
Thanks & Enjoy Elixir
Tobias Pfeiffer
@PragTob
pragtob.info
Photo Attribution
● CC BY-ND 2.0
– https://www.flickr.com/photos/mmmswan/8918529543/
● CC BY 2.0
– https://flic.kr/p/eKGRRJ
● CC BY-NC 2.0
– https://www.flickr.com/photos/-jule/2728475835/
– https://flic.kr/p/emoKPd
● CC BY-NC-ND 2.0
– https://flic.kr/p/eyC7ZT
– https://www.flickr.com/photos/75487768@N04/14029339573/
– https://flic.kr/p/bG2r2D
● CC BY-SA 2.0
– https://commons.wikimedia.org/wiki/File:Heckert_GNU_white.svg
– https://flic.kr/p/cEJDC3

More Related Content

What's hot

Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my dayTor Ivry
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School ProgrammersSiva Arunachalam
 
Closures
ClosuresClosures
ClosuresSV.CO
 
Intro to OTP in Elixir
Intro to OTP in ElixirIntro to OTP in Elixir
Intro to OTP in ElixirJesse Anderson
 
Elixir pattern matching and recursion
Elixir pattern matching and recursionElixir pattern matching and recursion
Elixir pattern matching and recursionBob Firestone
 
The secrets of inverse brogramming
The secrets of inverse brogrammingThe secrets of inverse brogramming
The secrets of inverse brogrammingRichie Cotton
 
Python fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuanPython fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuanWei-Yuan Chang
 
Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2Raghu nath
 
python chapter 1
python chapter 1python chapter 1
python chapter 1Raghu nath
 
Functional Pattern Matching on Python
Functional Pattern Matching on PythonFunctional Pattern Matching on Python
Functional Pattern Matching on PythonDaker Fernandes
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecturemobl - model-driven engineering lecture
mobl - model-driven engineering lecturezefhemel
 
The Ring programming language version 1.7 book - Part 26 of 196
The Ring programming language version 1.7 book - Part 26 of 196The Ring programming language version 1.7 book - Part 26 of 196
The Ring programming language version 1.7 book - Part 26 of 196Mahmoud Samir Fayed
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークTsuyoshi Yamamoto
 

What's hot (20)

Begin with Python
Begin with PythonBegin with Python
Begin with Python
 
Slides
SlidesSlides
Slides
 
Codigos
CodigosCodigos
Codigos
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School Programmers
 
Closures
ClosuresClosures
Closures
 
Python tutorial
Python tutorialPython tutorial
Python tutorial
 
Intro to OTP in Elixir
Intro to OTP in ElixirIntro to OTP in Elixir
Intro to OTP in Elixir
 
Elixir pattern matching and recursion
Elixir pattern matching and recursionElixir pattern matching and recursion
Elixir pattern matching and recursion
 
Intro
IntroIntro
Intro
 
Py3k
Py3kPy3k
Py3k
 
The secrets of inverse brogramming
The secrets of inverse brogrammingThe secrets of inverse brogramming
The secrets of inverse brogramming
 
Python fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuanPython fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuan
 
Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2
 
python chapter 1
python chapter 1python chapter 1
python chapter 1
 
Functional Pattern Matching on Python
Functional Pattern Matching on PythonFunctional Pattern Matching on Python
Functional Pattern Matching on Python
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecturemobl - model-driven engineering lecture
mobl - model-driven engineering lecture
 
FPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixirFPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixir
 
The Ring programming language version 1.7 book - Part 26 of 196
The Ring programming language version 1.7 book - Part 26 of 196The Ring programming language version 1.7 book - Part 26 of 196
The Ring programming language version 1.7 book - Part 26 of 196
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトーク
 

Similar to Elixir & Phoenix – fast, concurrent and explicit

Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitTobias Pfeiffer
 
Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitTobias Pfeiffer
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter InternalsPedro Medeiros
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a MomentSergio Gil
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?osfameron
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma IntroduçãoÍgor Bonadio
 
Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHdevbash
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missTobias Pfeiffer
 
Produce nice outputs for graphical, tabular and textual reporting in R-Report...
Produce nice outputs for graphical, tabular and textual reporting in R-Report...Produce nice outputs for graphical, tabular and textual reporting in R-Report...
Produce nice outputs for graphical, tabular and textual reporting in R-Report...Dr. Volkan OBAN
 
GE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingGE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingMuthu Vinayagam
 
Something about Golang
Something about GolangSomething about Golang
Something about GolangAnton Arhipov
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a bossgsterndale
 
Future vs. Monix Task
Future vs. Monix TaskFuture vs. Monix Task
Future vs. Monix TaskHermann Hueck
 
(first '(Clojure.))
(first '(Clojure.))(first '(Clojure.))
(first '(Clojure.))niklal
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Codestasimus
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 

Similar to Elixir & Phoenix – fast, concurrent and explicit (20)

Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
 
Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicit
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter Internals
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a Moment
 
Introducing Elixir
Introducing ElixirIntroducing Elixir
Introducing Elixir
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma Introdução
 
Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASH
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might miss
 
Produce nice outputs for graphical, tabular and textual reporting in R-Report...
Produce nice outputs for graphical, tabular and textual reporting in R-Report...Produce nice outputs for graphical, tabular and textual reporting in R-Report...
Produce nice outputs for graphical, tabular and textual reporting in R-Report...
 
GE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingGE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python Programming
 
Something about Golang
Something about GolangSomething about Golang
Something about Golang
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a boss
 
Python slide
Python slidePython slide
Python slide
 
Future vs. Monix Task
Future vs. Monix TaskFuture vs. Monix Task
Future vs. Monix Task
 
Basics
BasicsBasics
Basics
 
Tres Gemas De Ruby
Tres Gemas De RubyTres Gemas De Ruby
Tres Gemas De Ruby
 
(first '(Clojure.))
(first '(Clojure.))(first '(Clojure.))
(first '(Clojure.))
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 

More from Tobias Pfeiffer

Metaphors are everywhere: Ideas to Improve Software Development
 Metaphors are everywhere: Ideas to Improve Software Development  Metaphors are everywhere: Ideas to Improve Software Development
Metaphors are everywhere: Ideas to Improve Software Development Tobias Pfeiffer
 
Elixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and ExplicitElixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and ExplicitTobias Pfeiffer
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among HumansTobias Pfeiffer
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among HumansTobias Pfeiffer
 
Do You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About ItDo You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About ItTobias Pfeiffer
 
Elixir, your Monolith and You
Elixir, your Monolith and YouElixir, your Monolith and You
Elixir, your Monolith and YouTobias Pfeiffer
 
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Tobias Pfeiffer
 
It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)Tobias Pfeiffer
 
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
 Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version) Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)Tobias Pfeiffer
 
Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?Tobias Pfeiffer
 
How fast is it really? Benchmarking in Practice (Ruby Version)
How fast is it really? Benchmarking in Practice (Ruby Version)How fast is it really? Benchmarking in Practice (Ruby Version)
How fast is it really? Benchmarking in Practice (Ruby Version)Tobias Pfeiffer
 
Introducing Elixir the easy way
Introducing Elixir the easy wayIntroducing Elixir the easy way
Introducing Elixir the easy wayTobias Pfeiffer
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?Tobias Pfeiffer
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?Tobias Pfeiffer
 
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...Tobias Pfeiffer
 
Beating Go Thanks to the Power of Randomness
Beating Go Thanks to the Power of RandomnessBeating Go Thanks to the Power of Randomness
Beating Go Thanks to the Power of RandomnessTobias Pfeiffer
 

More from Tobias Pfeiffer (20)

Going Staff
Going StaffGoing Staff
Going Staff
 
Stories in Open SOurce
Stories in Open SOurceStories in Open SOurce
Stories in Open SOurce
 
Metaphors are everywhere: Ideas to Improve Software Development
 Metaphors are everywhere: Ideas to Improve Software Development  Metaphors are everywhere: Ideas to Improve Software Development
Metaphors are everywhere: Ideas to Improve Software Development
 
Stories in Open Source
Stories in Open SourceStories in Open Source
Stories in Open Source
 
Elixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and ExplicitElixir & Phoenix – Fast, Concurrent and Explicit
Elixir & Phoenix – Fast, Concurrent and Explicit
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among Humans
 
Functioning Among Humans
Functioning Among HumansFunctioning Among Humans
Functioning Among Humans
 
Do You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About ItDo You Need That Validation? Let Me Call You Back About It
Do You Need That Validation? Let Me Call You Back About It
 
Elixir, your Monolith and You
Elixir, your Monolith and YouElixir, your Monolith and You
Elixir, your Monolith and You
 
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
 
Where do Rubyists go?
 Where do Rubyists go?  Where do Rubyists go?
Where do Rubyists go?
 
It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)It's About the Humans, Stupid (Lightning)
It's About the Humans, Stupid (Lightning)
 
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
 Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version) Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
 
Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?Code, Comments, Concepts, Comprehension – Conclusion?
Code, Comments, Concepts, Comprehension – Conclusion?
 
How fast is it really? Benchmarking in Practice (Ruby Version)
How fast is it really? Benchmarking in Practice (Ruby Version)How fast is it really? Benchmarking in Practice (Ruby Version)
How fast is it really? Benchmarking in Practice (Ruby Version)
 
Introducing Elixir the easy way
Introducing Elixir the easy wayIntroducing Elixir the easy way
Introducing Elixir the easy way
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?
 
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
 
Beating Go Thanks to the Power of Randomness
Beating Go Thanks to the Power of RandomnessBeating Go Thanks to the Power of Randomness
Beating Go Thanks to the Power of Randomness
 

Recently uploaded

Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 

Recently uploaded (20)

Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 

Elixir & Phoenix – fast, concurrent and explicit

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7. Elixir and Phoenix fast, concurrent and explicit Tobias Pfeiffer @PragTob pragtob.info
  • 8. Elixir and Phoenix fast, concurrent and explicit Tobias Pfeiffer @PragTob pragtob.info
  • 9.
  • 11. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end
  • 12. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Ruby-like Syntax
  • 13.
  • 14. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end First-class functions
  • 15. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Tail-Call Optimization
  • 16. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Doctesting
  • 17. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Pattern Matching
  • 18. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Piotr Szotkowski"}) do IO.puts "Hi Piotr, awesome keyboards!" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Piotr Szotkowski"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 19. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Piotr Szotkowski"}) do IO.puts "Hi Piotr, awesome keyboards!" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Piotr Szotkowski"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 20. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Piotr Szotkowski"}) do IO.puts "Hi Piotr, awesome keyboards!" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Piotr Szotkowski"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 21. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Piotr Szotkowski"}) do IO.puts "Hi Piotr, awesome keyboards!" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Piotr Szotkowski"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 22. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Piotr Szotkowski"}) do IO.puts "Hi Piotr, awesome keyboards!" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Piotr Szotkowski"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 23. defmacro plug(plug, opts []) do quote do @plugs {unquote(plug), unquote(opts), true} end end Meta Programming
  • 24. defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end defimpl Blank, for: Map do def blank?(map), do: map_size(map) == 0 end defimpl Blank, for: Atom do def blank?(false), do: true def blank?(nil), do: true def blank?(_), do: false end Polymorphism
  • 25. defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end defimpl Blank, for: Map do def blank?(map), do: map_size(map) == 0 end defimpl Blank, for: Atom do def blank?(false), do: true def blank?(nil), do: true def blank?(_), do: false end Polymorphism
  • 26. defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end defimpl Blank, for: Map do def blank?(map), do: map_size(map) == 0 end defimpl Blank, for: Atom do def blank?(false), do: true def blank?(nil), do: true def blank?(_), do: false end Polymorphism
  • 27. @spec all?(t) :: boolean @spec all?(t, (element -> as_boolean(term))) :: boolean def all?(enumerable, fun fn(x) -> x end) def all?(enumerable, fun) when is_list(enumerable) and is_function(fun, 1) do do_all?(enumerable, fun) end Implemented in itself!
  • 28. @spec all?(t) :: boolean @spec all?(t, (element -> as_boolean(term))) :: boolean def all?(enumerable, fun fn(x) -> x end) def all?(enumerable, fun) when is_list(enumerable) and is_function(fun, 1) do do_all?(enumerable, fun) end Optional Type Annotations
  • 29. defmodule Plug do @type opts :: tuple | atom | integer | float | [opts] @callback init(opts) :: opts @callback call(Plug.Conn.t, opts) :: Plug.Conn.t end “Interfaces”
  • 30. defmodule Plug do @type opts :: tuple | atom | integer | float | [opts] @callback init(opts) :: opts @callback call(Plug.Conn.t, opts) :: Plug.Conn.t end “Interfaces”
  • 31. defmodule Plug.Head do @behaviour Plug alias Plug.Conn def init([]), do: [] def call(%Conn{method: "HEAD"} = conn, []) do %{conn | method: "GET"} end def call(conn, []), do: conn end “Interfaces”
  • 32. defmodule Plug.Head do @behaviour Plug alias Plug.Conn def init([]), do: [] def call(%Conn{method: "HEAD"} = conn, []) do %{conn | method: "GET"} end def call(conn, []), do: conn end “Interfaces”
  • 34.
  • 35.
  • 36.
  • 37. 2.2.2 :001 > [1, 2, 3, 4].map { |i| i + 1 } => [2, 3, 4, 5] iex(2)> Enum.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] vs Where to call functions
  • 39. Pipe people = DB.find_customers orders = Orders.for_customers(people) tax = sales_tax(orders, 2013) filing = prepare_filing(tax)
  • 40. filing = DB.find_customers |> Orders.for_customers |> sales_tax(2013) |> prepare_filing Pipe
  • 42. filing = DB.find_customers |> Orders.for_customers |> sales_tax(2013) |> prepare_filing Pipe
  • 44. person = Person.new(attributes) person = do_something(person) insert_in_db(person) Immutable Data
  • 45.
  • 51. First class actor support
  • 52. OTP
  • 55.
  • 56. connection |> endpoint |> router |> pipelines |> controller |> model |> view Flow
  • 57. scope "/", Rumbl do pipe_through :browser get "/", PageController, :index resources "/users", UserController, only: [:index, :show, :new, :create] resources "/sessions", SessionController, only: [:new, :create, :delete] get "/watch/:id", WatchController, :show end Routes
  • 58. scope "/", Rumbl do pipe_through :browser get "/", PageController, :index resources "/users", UserController, only: [:index, :show, :new, :create] resources "/sessions", SessionController, only: [:new, :create, :delete] get "/watch/:id", WatchController, :show end Routes
  • 59. pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers plug Rumbl.Auth, repo: Rumbl.Repo end pipeline :api do plug :accepts, ["json"] end Pipelines
  • 60. def new(conn, _params) do changeset = User.new_changeset(%User{}) render conn, "new.html", changeset: changeset end Controller
  • 61. defmodule Rumbl.User do use Rumbl.Web, :model schema "users" do field :name, :string field :username, :string field :password, :string, virtual: true field :password_hash, :string has_many :videos, Rumbl.Video timestamps end # ... end Model
  • 62. defmodule Rumbl.UserView do use Rumbl.Web, :view alias Rumbl.User def first_name(%{name: name}) do name |> String.split(" ") |> Enum.at(0) end end View
  • 63. <%= form_for @changeset, user_path(@conn, :create), fn form -> %> <div class="form-group"> <%= text_input form, :name, placeholder: "Name", class: "form-control" %> <%= error_tag form, :name %> </div> <div class="form-group"> <%= text_input form, :username, placeholder: "Username", class: "form-control" %> <%= error_tag form, :username %> </div> <div class="form-group"> <%= password_input form, :password, placeholder: "Password", class: "form-control" %> <%= error_tag form, :password %> </div> <%= submit "Create User", class: "btn btn-primary" %> <% end %> Template
  • 64.
  • 65. def new_changeset(model, params %{}) do model |> cast(params, ~w(name username), []) |> unique_constraint(:username) |> validate_length(:username, min: 1, max: 20) end def registration_changeset(model, params) do model |> new_changeset(params) |> cast(params, ~w(password), []) |> validate_length(:password, min: 6, max: 100) |> put_pass_hash() end Changesets
  • 66. def new_changeset(model, params %{}) do model |> cast(params, ~w(name username), []) |> unique_constraint(:username) |> validate_length(:username, min: 1, max: 20) end def registration_changeset(model, params) do model |> new_changeset(params) |> cast(params, ~w(password), []) |> validate_length(:password, min: 6, max: 100) |> put_pass_hash() end Changesets
  • 67. def new_changeset(model, params %{}) do model |> cast(params, ~w(name username), []) |> unique_constraint(:username) |> validate_length(:username, min: 1, max: 20) end def registration_changeset(model, params) do model |> new_changeset(params) |> cast(params, ~w(password), []) |> validate_length(:password, min: 6, max: 100) |> put_pass_hash() end Changesets
  • 68. def create(conn, %{"user" => user_params}) do changeset = User.registration_changeset(%User{}, user_params) case Repo.insert changeset do {:ok, user} -> conn |> Rumbl.Auth.login(user) |> put_flash(:info, "You successfully registered!") |> redirect(to: user_path(conn, :index)) {:error, changeset}-> render conn, "new.html", changeset: changeset end end Changesets
  • 69. defmodule Rumbl.VideoChannel do use Rumbl.Web, :channel def join("videos:" <> video_id, _params, socket) do {:ok, socket} end def handle_in("new_annotation", params, socket) do broadcast! socket, "new_annotation", %{ user: %{username: "anon"}, body: params["body"], at: params["at"] } {:reply, :ok, socket} end end Channels
  • 71. iex(13)> user = Repo.get_by(User, name: "Homer") iex(14)> user.videos #Ecto.Association.NotLoaded<association :videos is not loaded> Explicit preloading
  • 72. iex(13)> user = Repo.get_by(User, name: "Homer") iex(14)> user.videos #Ecto.Association.NotLoaded<association :videos is not loaded> Explicit preloading
  • 73. iex(15)> Repo.preload(user, :videos) iex(16)> user.videos #Ecto.Association.NotLoaded<association :videos is not loaded> Explicit preloading
  • 74. iex(17)> user = Repo.preload(user, :videos) iex(18)> user.videos [%Rumbl.Video{__meta__: #Ecto.Schema.Metadata<:loaded>, category: #Ecto.Association.NotLoaded<association :category is not loaded>, category_id: nil, description: "such great many wow", id: 3, inserted_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, title: "Hubidubiee", updated_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, url: "www.lol.com", user: #Ecto.Association.NotLoaded<association :user is not loaded>, user_id: 5}] Explicit preloading
  • 75. So we all go and do Elixir and Phoenix now?
  • 76.
  • 81. So, would you start a new project in Elixir and Phoenix now? Q&A question #1
  • 84. Thanks & Enjoy Elixir Tobias Pfeiffer @PragTob pragtob.info
  • 85. Photo Attribution ● CC BY-ND 2.0 – https://www.flickr.com/photos/mmmswan/8918529543/ ● CC BY 2.0 – https://flic.kr/p/eKGRRJ ● CC BY-NC 2.0 – https://www.flickr.com/photos/-jule/2728475835/ – https://flic.kr/p/emoKPd ● CC BY-NC-ND 2.0 – https://flic.kr/p/eyC7ZT – https://www.flickr.com/photos/75487768@N04/14029339573/ – https://flic.kr/p/bG2r2D ● CC BY-SA 2.0 – https://commons.wikimedia.org/wiki/File:Heckert_GNU_white.svg – https://flic.kr/p/cEJDC3