ELIXIR
QUE POÇÃO É ESSA?
MATA56 - Paradigmas de Linguagens de Programação
16/05/2016
Alesson Bruno, Cristiano Santos e Felipe Rabello
HISTÓRIA
ERLANG?
TEMPO REAL
CONCORRÊNCIA
DISTRIBUÍDO
TOLERÂNCIA A FALHAS
TEMPO REAL
CONCORRÊNCIA
DISTRIBUÍDO
TOLERÂNCIA A FALHAS
"FEIA"
DESDE 1996
2012
- DIFERENTES CONSTRUTORES
- EXCELENTE FERRAMENTAL
- METAPROGRAMAÇÃO
- POLIMORFISMO (PROTOCOLS)
- MACROS
- E MAIS ...
LICENÇA
Direitos reservados da Plataformatec
Código fonte: Apache 2 License
E POR QUE ELIXIR?
ZILHÕES DE TRANSISTORES
MUITOS NÚCLEOS
COMO MANTÊ-LOS OCUPADOS?
EXPLORANDO TRABALHO
E POR QUE ELIXIR?
FUNCIONAL E CONCORRENTE
FUNCIONAL NÃO PRECISA SER MATEMÁTICO
NEM COMPLEXO
E POR QUE ELIXIR?
FUNCIONAL E CONCORRENTE
CONCORRENTE SEM ABSTRAÇÕES COMO:
LOCKS E SEMÁFOROS
PARADIGMAS SUPORTADOS
MULTI PARADIGMA
FUNCIONAL, CONCORRENTE, DISTRIBUÍDO E
ORIENTADO A PROCESSOS
COMPILADA, INTERPRETADA OU HÍBRIDA?
COMPILADA PARA O BYTECODE DA MÁQUINA DO ERLANG (BEAM)
GERENCIAMENTO DE MEMÓRIA
ERLANG POSSUI GARBAGE COLLECTOR (GC)
ELIXIR RODA EM CIMA DA MÁQUINA DO ERLANG
ELIXIR TAMBÉM POSSUI GC
GERENCIAMENTO DE MEMÓRIA
MILHARES DE PROCESSOS CONCORRENTES
PROCESSOS ISOLADOS COM GC INDEPENDENTE
REDUZ PAUSAS
UTILIZA MAIS RECURSOS DA MÁQUINA EFICIENTEMENTE
SELEÇÃO
CASE, COND E IF
SELEÇÃO
CASE
case {1, 2, 3} do
{4, 5, 6} ->
"This clause won't match"
{1, x, 3} ->
"This clause will match and bind x to 2 in this clause"
_ ->
"This clause would match any value"
end
# output
"This clause will match and bind x to 2 in this clause"
SELEÇÃO
COND
cond do
2 + 2 == 5 ->
"This will not be true"
2 * 2 == 3 ->
"Nor this"
1 + 1 == 2 ->
"But this will"
end
# output
"But this will"
SELEÇÃO
IF E UNLESS
if true do
"This works!"
end
# output
"This works!"
unless true do
"This will never be seen"
end
REPETIÇÃO
LOOPS EM ELIXIR (ASSIM COMO EM OUTRA LINGUAGEM FUNCIONAL) SÃO ESCRITOS DE FORMA DIFERENTE DAS LINGUAGENS IMPERATIVAS
USAR RECURSÃO, REDUCE, MAP, ...
REPETIÇÃO
RECURSÃO
defmodule Recursion do
def print_multiple_times(msg, n) when n <= 1 do
IO.puts msg
end
def print_multiple_times(msg, n) do
IO.puts msg
print_multiple_times(msg, n - 1)
end
end
Recursion.print_multiple_times("Hello!", 3)
# Hello!
# Hello!
# Hello!
REPETIÇÃO
O PODER DA RECURSÃO
defmodule Math do
def sum_list([head | tail], accumulator) do
sum_list(tail, head + accumulator)
end
def sum_list([], accumulator) do
accumulator
end
end
IO.puts Math.sum_list([1, 2, 3], 0) #=> 6
REPETIÇÃO
REDUCE E MAP
Enum.reduce([1, 2, 3], 0, fn(x, acc) -> x + acc end)
# output
6
Enum.map([1, 2, 3], fn(x) -> x * 2 end)
# output
[2, 4, 6]
AFINAL, É BOM?
RESTRIÇÕES DE IDENTIFICADORES
AS VARIÁVEIS EM ELIXIR DEVEM COMEÇAR COM LETRA MINÚSCULA OU UM UNDERSCORE (_), TEREM UM OU MAIS CARACTERES, SENDO ELES LETRAS, NÚMEROS OU UNDERSCORE (_). NÃO PODEM SER KEYWORDS
CASE SENSITIVE
AS VARIÁVEIS EM ELIXIR SÃO CASE SENSITIVE. LOGO, someVar, somevar E SOMEVAR SÃO VARIÁVEIS DIFERENTES
TIPAGEM
ELIXIR É UMA LINGUAGEM DINAMICAMENTE TIPADA, LOGO, NÃO PRECISAMOS DEFINIR O TIPO DAS VÁRIAVEIS QUANDO INICIADAS, SEU TIPO É ATRIBUÍDO EM TEMPO DE EXECUÇÃO. ELA TAMBÉM É FORTEMENTE TIPADA.
PATTERN MATCHING
MATCH OPERATOR
# Assign value
x = 1
IO.puts x # 1
# Match operator
1 = x
# 1
2 = x
** (MatchError) no match of right hand side value: 1
PATTERN MATCHING
MATCH OPERATOR
{a, b, c} = {:hello, "world", 42}
# {:hello, "world", 42}
[a, b, c] = [1, 2, 3]
# [1, 2, 3]
[head | tail] = [1, 2, 3]
# [1, 2, 3]
head
# 1
tail
# [2, 3]
MUTABILIDADE
OS TIPOS DE DADOS EM ELIXIR SÃO IMUTÁVEIS. ISSO SIGNIFICA QUE, MODIFICANDO UMA VARIÁVEL, O ELIXIR RETORNA UMA NOVA ESTRUTURA. SENDO IMUTÁVEL, VOCÊ NÃO PRECISA SE PREOCUPAR QUE UM BLOCO DE CÓDIGO PARTICULAR ESTÁ MUTANDO SUA ESTRUTURA DE DADOS EM ALGUM LUGAR.
FUNÇÕES ANINHADAS
O ELIXIR NÃO SUPORTA FUNÇÕES ANINHADAS. PELAS SUAS REGRAS DE ESCOPO, PODEMOS ANINHAR MÓDULOS, E PARA CADA MÓDULO ANINHADO, DEFINIR FUNÇÕES.
FUNÇÕES ANINHADAS
defmodule P do
defmodule Q do
def q(false), do: "sorry"
def q(true) do
defmodule M do
def say, do: "hi"
end
end
end
end
P.Q.q false #=> "sorry"
# the module hasn't been defined yet
P.Q.M.say #=> undefined function: P.Q.M.say/0
# after this call the P.Q.M module will become available
P.Q.q true
P.Q.M.say #=> "hi"
CIDADÃOS DE PRIMEIRA CLASSE
EM ELIXIR, AS FUNÇÕES ANÔNIMAS SÃO AS FUNÇÕES COMO CIDADÃOS DE PRIMEIRA CLASSE
defmodule Math do
def square(x) do
x * x
end
end
Enum.map [1, 2, 3], &Math.square/1
#=> [1, 4, 9]
CIDADÃOS DE PRIMEIRA CLASSE
CLOSURES
closures = []
i = 0
closures = closures ++ [fn -> IO.puts i end]
i = 1
closures = closures ++ [fn -> IO.puts i end]
i = 2
closures = closures ++ [fn -> IO.puts i end]
Enum.at(closures, 0).()
Enum.at(closures, 1).()
Enum.at(closures, 2).()
# 0
# 1
# 2
GERENCIAMENTO DE DEPENDÊNCIAS
MIX
MIX
$ mix new example
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/example.ex
* creating test
* creating test/test_helper.exs
* creating test/example_test.exs
MIX
defmodule Example.Mixfile do
use Mix.Project
def project do
[app: :example,
version: "0.0.1",
elixir: "~> 1.0",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end
def application do
[applications: [:logger]]
end
defp deps do
[]
end
end
MIX
def deps do
[{:phoenix, "~> 0.16"},
{:phoenix_html, "~> 2.1"},
{:cowboy, "~> 1.0", only: [:dev, :test]},
{:slim_fast, ">= 0.6.0"}]
end
$ mix deps.get
EM ELIXIR, TODO O CÓDIGO RODA EM PROCESSOS. PROCESSOS SÃO ISOLADOS UM DOS OUTROS, SÃO CONCORRENTES E SE COMUNICAM POR MENSAGENS.
CONCORRÊNCIA
OS PROCESSOS DO ELIXIR NÃO DEVEM SER CONFUNDIDOS COM OS PROCESSOS DO SISTEMA OPERACIONAL. ELES SÃO BEM LEVES EM TERMOS DE MEMÓRIA E CPU. POR CAUSA DISSO, NÃO É INCOMUM TER DEZENAS OU ATÉ CENTENAS DE MILHARES DE PROCESSOS RODANDO SIMULTANEAMENTE
CONCORRÊNCIA
parent = self()
#PID<0.41.0>
spawn fn -> send(parent, {:hello, self()}) end
#PID<0.48.0>
receive do
{:hello, pid} -> "Got hello from #{inspect pid}"
end
# output
"Got hello from #PID<0.48.0>"
ALGUÉM REALMENTE TEM DÚVIDAS?
Elixir
By cristianossd
Elixir
Describing elixir language
- 757