IO.puts("Hello, world")
Dissecando
IO.puts("Hello, world")
IO
Módulo
IO.puts("Hello, world")
puts
Função
IO.puts("Hello, world")
( )
Invocação da função
IO.puts("Hello, world")
"Hello, world!"
Argumento
Assinatura em Elixir: MFA (Modulo, Função e Aridade)
IO.puts("Hello, world")
IO.puts/1
Dado o arquivo meu_programa.exs
year_of_birth = IO.gets("Qual ano você nasceu? ")
year_of_birth = String.trim(year_of_birth)
year_of_birth = String.to_integer(year_of_birth)
today = Date.utc_today()
age = today.year - year_of_birth
IO.puts("Você tem #{age} anos.")
$ elixir meu_programa.exs
Dado o arquivo meu_programa.js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Qual ano você nasceu? ', (answer) => {
const birthYear = parseInt(answer);
const currentYear = new Date().getFullYear();
const age = currentYear - birthYear;
console.log(`Você tem ${age} anos.`);
rl.close();
});
$ node meu_programa.js
1 # integer
0x1F # integer
1.0 # float
true # boolean
:atom # atom / symbol
"elixir" # string
[1, 2, 3] # list
{1, 2, 3} # tuple
Módulos são uma forma de organizar funções são definidas com a palavra
chave defmodule
. Note que o escopo é definido como as palavras chaves
do
e end
. Isso serve para funções e macros também.
defmodule MyModule do
# code here
end
Funções são definidas dentro de módulos com a palavra-chave def
.
defmodule MyModule do
def greet(name) do
IO.puts("Hello, #{name}")
end
end
MyModule.greet("Vinícius") # => Hello, Vinícius!
Módulos agem como namespaces
em um programa de Elixir
defmodule MyApp.Math do
def add(n, n2) do
n + n2
end
end
defmodule MyApp.Main do
def run() do
MyApp.Math.add(1, 2)
end
end
Sem múltiplas atribuições:
year_of_birth = String.to_integer(String.trim(IO.gets("Qual ano você nasceu? ")))
today = Date.utc_today()
age = today.year - year_of_birth
IO.puts("Você tem #{age} anos.")
O operador pipe (|>)
serve para atribuir o retorno da última expressão
como primeiro argumento da próxima.
year_of_birth =
"Qual ano você nasceu? " # primeira expressão -> String
|> IO.gets() # segunda expressão -> gets(resultado da primeira)
|> String.trim() # terceira expressão -> trim(resultado da segunda)
|> String.to_integer() # ultima expressão -> to_integer(resultado da terceira)
today = Date.utc_today()
age = today.year - year_of_birth
IO.puts("Você tem #{age} anos.")
Pseudo código equivalente em JavaScript:
"Qual ano você nasceu"
.gets()
.trim()
.to_integer()
Onde Elixir roda?
Processo é uma unidade de execução de código sequencial.
Processos são tão baratos de serem criados em Elixir/Erlang que existem processos só para supervisionar outros processos.
O modelo de concorrência do Erlang é baseado em um modelo preemptivo,
que calcula o número de reduções
que um processo teve e então o pausa
para que outro possa usar a CPU
.
Aumenta o número de Schedulers por CPU.
Um nó Erlang pode se conectar com outro via rede e trocar mensagens entre processos. Pode-se criar um cluster inteiro de nós Erlang.
https://blog.whatsapp.com/1-million-is-so-2011
2 milhões de usuários conectados em uma só máquina em 2012.
24 CPUS - 96 GB de memória - Intel Xeon x5670 @ 3.07Ghz
Uso de memória e CPU em 40%.
https://discord.com/blog/how-discord-scaled-elixir-to-5-000-000-concurrent-users
Discord usa cluster de Elixir/Erlang para servir 5 milhões de usuários.
Documentação em Elixir é um cidadão de primeira classe:
defmodule MyApp do
@moduledoc """
My app entrypoint
"""
@doc """
my function doc
"""
def run() do
end
end
Phoenix é o principal framework web do ecossistema.
Controller
defmodule HelloWeb.MyController do
use Phoenix.Controller
action_fallback HelloWeb.MyFallbackController
def show(conn, %{"id" => id}, current_user) do
with {:ok, post} <- fetch_post(id),
:ok <- authorize_user(current_user, :view, post) do
render(conn, :show, post: post)
end
end
end
Router
defmodule HelloWeb.Router do
use HelloWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, {HelloWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", HelloWeb do
pipe_through :browser
get "/", PageController, :home
end
# Other scopes may use custom stacks.
# scope "/api", HelloWeb do
# pipe_through :api
# end
# ...
end
Ecto é a biblioteca principal para lidar com dados no Elixir.
Exemplo de mapeamento de tabela.
defmodule Weather do
use Ecto.Schema
# weather is the DB table
schema "weather" do
field :city, :string
field :temp_lo, :integer
field :temp_hi, :integer
field :prcp, :float, default: 0.0
end
end
Exemplo de Query
import Ecto.Query, only: [from: 2]
query = from u in User,
where: u.age > 18 or is_nil(u.email),
select: u
# Returns %User{} structs matching the query
Repo.all(query)
GraphQL toolkit para Elixir.
Exemplo de definição de schema
defmodule BlogWeb.Schema do
use Absinthe.Schema
import_types BlogWeb.Schema.ContentTypes
alias BlogWeb.Resolvers
query do
@desc "Get all posts"
field :posts, list_of(:post) do
resolve &Resolvers.Content.list_posts/3
end
end
end
Extensão do Phoenix que permite criar páginas web dinâmicas sem escrevendo muito pouco ou quase nada de JavaScript.
defmodule TimelineLive do
use Phoenix.LiveView
def render(assigns) do
render("timeline.html", assigns)
end
def mount(_, socket) do
Twitter.subscribe("elixirphoenix")
{:ok, assign(socket, :tweets, [])}
end
def handle_info({:new, tweet}, socket) do
{:noreply,
update(socket, :tweets, fn tweets ->
Enum.take([tweet | tweets], 10)
end)}
end
end
Livebook é um notebook interativo e colaborativo de Elixir.