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

Science&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdfScience&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdfjimielynbastida
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 

Recently uploaded (20)

Science&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdfScience&tech:THE INFORMATION AGE STS.pdf
Science&tech:THE INFORMATION AGE STS.pdf
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 

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