Elixir is a dynamic, functional language designed for building scalable and maintainable applications.
¿Dinámico?
Evalua el tipo de dato durante el runtime
¿Lenguaje funcional?
Programación funcional es un paradigma de programación basado en el uso de funciones matemáticas que enfatiza los cambios de estado mediante la mutación de variables.
¿Escalable?
Elixir corre sobre la VM de Erlang conocida por su baja latencia, sistemas distribuidos y tolerante a fallos.
Lenguaje funcional orientado a la concurrencia, que al igual que elixir, esta diseñado para crear aplicaciones distribuidas, paralelas y/o concurrentes.
BEAM es parte del sistema del Runtime de Erlang que compila su código (y el de Elixir) a bytecode que a su vez es ejecutado en la misma.
Lo que hace potente a Elixir es BEAM (Maquina virtual de Erlang), su scheduler y el framework OTP.
Conjunto de módulos, bibliotecas, patrones de diseño y comportamientos que permiten crear aplicaciones concurrentes, tolerante a fallas y distribuidas.
El modelo de actor en ciencias de la computación es un modelo matemático de computación simultánea que trata a los “actores” como los primitivos universales de la computación concurrente.
El actor como unidad primitiva de computo, es aquella que recibe mensajes y realiza algún tipo de procesamiento en base al mensaje recibido.
Entonces, ¿El Actor es una cola de mensajes?
En Elixir (Erlang) la unidad minima de computo es un proceso, cada uno tiene un "mailbox" que recibe los mensajes, que son estructuras de datos simples e inmutables.
defmodule Hello do
def say_hi(name) do
"Hello #{name}, I'm world, nice to meet you"
end
end
defmodule Calculator do
def sum(a,b) do
a + b
end
def mul(a,b) do
a * b
end
def subs(a,b) do
a - b
end
end
defmodule Hello do
def say_hi(name) do
"Hello #{name}, I'm world, nice to meet you"
end
end
defmodule Calculator do
def sum(a,b) do
a + b
end
def mul(a,b) do
a * b
end
end
https://elixir-lang.org/getting-started/introduction.html
En Elixir (Erlang) no existe la asignación de variables sino la vinculación.
Existe el pattern matching.
iex(1)> a = 1
1
iex(2)> 2 = a
** (MatchError) no match of right hand side value: 1
El cáracter "=" no es un operador de asignación si no de match
iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}
iex> a
:hello
iex> b
"world"
iex> [d, e, f] = [1, 2, 3]
[1, 2, 3]
iex> d
1
iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
El operador match "=" también es util para desestructurar tipos de datos más complejos.
defmodule Calculator
def sum(a,b) do
a + b
end
def mult(a,b) do
a * b
end
def subs(a,b) do
a - b
end
def div(a, 0) do
:error
end
def div(a, b) do
a / b
end
end
Unidad minima de computo, todo el código de elixir corre en procesos que están aislados unos de otros, estos poseen su propia memoria, se ejecutan concurrentemente y se comunican vía paso de mensajes.
El comando `spawn` es el mecanismo básico para ejecutar procesos.
Los mismos son asíncronos y orquestados por el scheduler de BEAM.
Los procesos se pueden comunicar a través de los funciones `send/2` y `receive/1`
iex> send self(), {:hello, "world"}
{:hello, "world"}
iex> receive do
...> {:hello, msg} -> msg
...> {:world, msg} -> "won't match"
...> end
"world"
Conjunto de módulos, bibliotecas, patrones de diseño y comportamientos que permiten crear aplicaciones concurrentes, tolerante a fallas y distribuidas.
(behaviors)
Los comportamientos en OTP, son el producto de años de refinamiento de código puesto a prueba en producción.
Los OTP Behaviours ayudan a extraer de tu código el comportamiento genérico quedando el camino libre para trabajar en la implementación del negocio.
(behaviors)
Entre ellos existen
gen_server
gen_server
defmodule SimpleGenServerBehaviour do
use GenServer
def start_link() do
GenServer.start_link(__MODULE__, [])
end
def init(_) do
# runs in the server context
{:ok, 1}
end
# funciones del cliente
def get_data() do
GenServer.call(__MODULE__, :get_data)
end
def increment() do
GenServer.cast(__MODULE__, :increment)
end
# Funciones del Servidor
# Llamada sincrona
def handle_call(:get_data, _, state) do
# runs in the server context
{:reply, state, state}
end
# Llamada asincrona
def handle_cast(:increment, state) do
# runs in the server context
{:noreply, state + 1}
end
end
gen_server
iex> SimpleGenServerBehaviour.start_link()
{:ok, #PID<0.106.0>}
iex> SimpleGenServerBehaviour.get_data()
1
iex> SimpleGenServerBehaviour.increment()
:ok
iex> SimpleGenServerBehaviour.get_data()
2
iex>
supervisor
Los supervisores proveen un manera standard y especifica de como los procesos deben ser iniciados, monitoreados por fallas y reiniciados.
supervisor strategies
one_for_one
rest_for_one
one_for_all
Phoenix Web Framework
Absinthe