3. La communauté Elixir en effervescence
• En développement depuis 2011.
Le développement s’accélère depuis que le language est stable. Elixir 1.0
publié en septembre 2014, suivi de Elixir 1.1 en septembre 2015.
• Sortie du Framework de développement Web Phoenix en août 2015 en
version 1.0.
9. La communauté Elixir revitalise Erlang
• Une influence majeure sur la VM Erlang:
• Maps et optimisation des performances.
• Hex.pm
• Réflexion sur le langage
11. Une communauté active et décentralisée
• La participation aux
conférences Elixir est en
forte augmentation.
250 participants cette
année à la conférence
Elixir à Austin
• Des “meetups” dans le
monde entier
13. Les forces du langage: Ecosystème, influence
et communauté
• Des outils pensés dès la conception du langage pour la productivité:
• Mix
• Hex.pm
• exUnit
• Phoenix,
• exrm, …
• Un langage mêlant les influences:
• Influence d’Erlang (car construit sur la VM Erlang).
• Influence de Ruby et de Rails
• Influence de Lisp, C#, Python, Haskell, etc…
• Une communauté ouverte et accueillante. Les débutants sont accompagnés. Le
langage attire des développeurs auparavant rebuté par la syntaxe d’Erlang.
14. Cas d’usage modernes
• Elixir est bien adapté:
• aux systèmes de messaging en général:
• Exemples: ProcessOne / ejabberd.
• pour le développement Web, d’API et de “micro-services”, grâce au
framework Phoenix.
• Exemples: Plataformatec, Brightcove, Shopping Adventure
• au développement de DSL (Domain Specific Languages), grâce au
système de macros évolué d’Elixir,
• Les plates-formes transactionnelles de masse: Jeu vidéo, finance.
• Exemples: Undead Labs
• à l’informatique embarquée (Raspberry Pi, Beagle board).
• Exemples: Rose Point Navigation Systems.
• à la gestion de la masse de signaux produits par l’Internet of Things.
16. Les idées fortes d'Elixir
• Pattern matching
• Les fonctions transforment les données: Les "pipes" |>
• Meta-Programmation s’appuyant sur les macros.
• Extensibilité / Polymorphisme: Protocols.
• Shell puissant pour le debug et la gestion d’une plate-forme de production.
• Documentation dans le code accessible depuis la ligne de commande.
• “For Comprehension” / into.
• Performance et clustering natif.
• Compatibilité avec Erlang. Réutilise des années de travail sur la distribution et
le parallélisme et des centaines de milliers de ligne de code.
• Upgrade de code à chaud et release.
• Les patterns Erlang OTP: Supervisors, servers, etc
17. Pattern matching
• Le pattern matching permet d’écrire un code plus expressif, grâce à des
matches basés sur la forme et le contenu:
a = 1
{c,d} = {2, 3}
[e,f,g] = [4, 5, 6]
"Elixir " <> rest = "Elixir rocks"
=> # rest => "rocks"
[ head | tail ] = [ 1, 2, 3, 4, 5, 6 ]
=> # head => 1
# tail => [ 2, 3, 4 ,5 ,6]
^a = 2
=> ** (MatchError) no match of right hand side value: 2
18. Pattern matching
• Le pattern matching est utilisable partout, dans les fonctions, les cases, etc.
Exemple “case”:
case File.open("myfile") do
{ :ok, device } -> IO.read(device, :line)
{ :error, reason } -> IO.puts "FAILED #{reason}"
end
19. Pattern matching
• Le pattern matching est utilisable partout, dans les fonctions, les cases, etc.
Exemple fonctions anonymes:
my_fun = fn
:plus, a, b -> a + b
:times, a, b -> a * b
end
IO.puts my_fun.(:plus, 3, 4) # => 7
IO.puts my_fun.(:times, 3, 4) # => 12
def other_fun(:minus, a, b), do: a - b
def other_fun(:divide, a, b), do: a/b
20. Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. La spécification est:
fib(0) ⟶ 0
fib(1) ⟶ 1
fib(n) ⟶ fib(n-1) + fib(n-2)
21. Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. Pattern match 1:
defmodule Fib do
def fib(n) do
if n < 2 do
n
else
fib(n-1) + fib(n-2)
end
end
end
22. Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. Pattern match 2:
defmodule Fib do
def fib(n) do
case n do
0 -> 0
1 -> 1
n -> fib(n-1) + fib(n-2)
end
end
end
23. Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. Pattern match 3:
defmodule Fib do
def fib(0), do: 0
def fib(1), do: 1
def fib(n), do: fib(n-1) + fib(n-2)
end
A comparer à:
fib(0) ⟶ 0
fib(1) ⟶ 1
fib(n) ⟶ fib(n-1) + fib(n-2)
24. Les fonctions transforment les données: Les
"pipes" |>
• Un langage fonctionnel est basé sur des fonctions que l’on compose entre
elles pour transformer des données.
invite_template = read_email_template(:invite)
users = DB.ParisExUsers
emails = format_emails(users, invite_template)
send_invite_emails(emails)
• Il s’agit d’une composition de fonctions:
send_invite(format_emails(DB.ParisExUsers, read_email_template(:invite)))
25. Les fonctions transforment les données: Les
"pipes" |>
• Le pipeline est plus clair grâce au “sucre syntaxique” d’Elixir:
invite_template = read_email_template(:invite)
DB.ParisExUsers
|> format_emails(invite_template)
|> send_invite_emails
• Attention à ce que le premier paramètre de vos fonctions soit bien la donnée à
transformer et ce que les paramètres suivants soient bien les “options”.
26. Les macros Elixir sont au coeur du langage
• Exécutée pour transformer le code à la compilation.
• Inspirée de Lisp: quote / unquote: Injection de code non-exécuté à la
compilation:
• quote: injecter du code à la compilation
• unquote: merger avec du code inclut passé à la macro
• Elles ont sauvé (littéralement) le langage.
Attention !
• Les macros permettent de créer des DSL utiles, mais ne jamais utiliser une
macro lorsque l’on peut utiliser une fonction.
• Elle vous permettre de réécrire des parties du langage donc peuvent rendre le
code plus obscur et fragile en cas d’abus.
27. Exemple de macro: If clause
defmodule My do
defmacro if(condition, clauses) do
do_clause = Keyword.get(clauses, :do, nil)
else_clause = Keyword.get(clauses, :else, nil)
quote do
case unquote(condition) do
val when val in [false, nil] -> unquote(else_clause)
_ -> unquote(do_clause)
end
end
end
end
28. Exemple de macro: If clause
defmodule Test do
require My
My.if 1 == 2 do
IO.puts "1 == 2"
else
IO.puts "1 != 2"
end
end
Usage:
$ elixir myif.exs
1 != 2
29. Elixir et les protocoles
• Les protocoles sont la manières dont Elixir implémente le polymorphisme.
• Ils permettent:
• d’implémenter des fonctionnalités dans un module sans avoir à modifier le
code du module
• d’abstraire un comportement commun à un ensemble de module mais de
permettre de spécialiser / surcharger le comportement.
• d’étendre le langage avec ses propres modules tout en s’intégrant
élégamment dans le langage Elixir.
30. Exemple: Le protocole inspect
• Voici la définition du protocole Inspect:
defprotocol Inspect do
@fallback_to_any true
def inspect(thing, opts)
end
• Ce protocole permet d’afficher de manière élégante des structures de
données, y compris vos propres structures.
31. Implémenter le protocole Inspect
Un cas typique consiste à impriment Inspect dans une struct:
defmodule User do
defstruct name: "John", age: 27
defimpl Inspect do
def inspect(%User{name: name, age: age}, _opts) do
"username is #{name} and age is #{age}"
end
end
end
32. Implémenter le protocole Inspect
• Voici le code qui démontre l’usage d’Inspect pour notre struct:
defmodule Test do
require User
users = [%User{},
%User{name: "Meg", age: 30},
%User{name: "Luke", age: 28}]
Enum.each users, fn user ->
IO.puts "#{inspect user}"
end
end
Usage:
$ elixir example_inspect.exs
username is John and age is 27
username is Meg and age is 30
username is Luke and age is 28
33. Redefinir une implémentation de protocole
• Interactive Elixir (1.1.1) - press Ctrl+C to exit (type h() ENTER for
help)
• iex(1)> inspect self
• "#PID<0.57.0>"
• iex(2)> defimpl Inspect, for: PID do
• ...(2)> def inspect(pid, _) do
• ...(2)> "Mon identifiant de process est "
<> :erlang.list_to_binary(:erlang.pid_to_list(pid))
• ...(2)> end
• ...(2)> end
• iex:2: warning: redefining module Inspect.PID
• {:module, Inspect.PID, …}
• iex(3)> inspect self
• "Mon identifiant de process est <0.57.0>"
34. Conclusion
• Je reprends les termes de Dave Thomas, l’auteur de “Programming Elixir” et
le co-fondateur de “The Pragmatic Programmers”:
Pensons différemment !
• Elixir est une opportunité
• Ne recréons pas l’environnement d’où nous venons
• Amusons-nous