Elixir 1.18 en 2026: el sistema de tipos gradual y las novedades reales del lenguaje

Elixir 1.18 se publicó en diciembre de 2024 y trajo algo que muchos llevaban tiempo esperando: los primeros pasos reales hacia un sistema de tipos en un lenguaje que, hasta ahora, era completamente dinámico. No es un cambio radical de un día para otro, pero marca una dirección clara. Si usas Elixir o estás pensando en aprenderlo, merece la pena entender qué hay detrás.

Un poco de contexto sobre Elixir y su historia

José Valim creó Elixir en 2011 mientras trabajaba en el núcleo de Rails. Su objetivo no era reinventar la rueda, sino aprovechar la solidez de la BEAM, la máquina virtual de Erlang, con una sintaxis más moderna y herramientas que facilitaran el desarrollo. La primera versión estable, 1.0, llegó en 2014, y desde entonces el lenguaje no ha parado de crecer.

La BEAM lleva décadas funcionando en sistemas de telecomunicaciones donde el tiempo de actividad se mide en años, no en horas. Ericsson la usa en sus switches, WhatsApp la usó para gestionar millones de conexiones simultáneas con un equipo minúsculo. Elixir hereda todo eso: tolerancia a fallos, concurrencia masiva y distribución sin apenas fricción.

Las versiones 1.16 (enero 2024) y 1.17 (junio 2024) fueron lanzamientos más incrementales. La 1.18 es donde ocurre algo cualitativamente distinto.

El sistema de tipos gradual: qué es y cómo funciona

Elixir 1.18 introduce un sistema de tipos basado en set-theoretic types, también llamados tipos de intersección y unión. La idea subyacente viene de la investigación académica, concretamente del trabajo de Giuseppe Castagna sobre tipos poliMórficos, y fue adaptada por el equipo de Elixir liderado por Guillaume Duboc junto con Valim.

Lo que distingue este enfoque de, por ejemplo, TypeScript, es que el sistema infiere tipos sin que tengas que anotarlos. En 1.18, el compilador ya puede emitir warnings cuando detecta que una función recibe o devuelve un tipo que no cuadra:

defmodule Calculadora do
  def suma(a, b) when is_integer(a) and is_integer(b) do
    a + b
  end
end

# Esto ahora genera un warning en compilación:
Calculadora.suma("hola", 42)
# warning: la función espera integer(), recibió binary()

No es un error de compilación, sino un warning. El lenguaje sigue siendo dinámico: el código compila y corre. Pero el compilador te avisa de que algo huele mal antes de que lo veas en producción.

Set-theoretic types: la base matemática

La gracia de los tipos de teoría de conjuntos es que permiten expresar cosas como "este valor puede ser un entero o un átomo, pero no una cadena". En la notación que usa Elixir internamente:

# Un tipo unión: integer() o atom()
# Un tipo intersección: map() con clave :ok
# Un tipo negación: no es nil

# El compilador infiere automáticamente a partir de guards:
def procesar(valor) when is_integer(valor) or is_atom(valor) do
  # Aquí el tipo inferido es integer() | atom()
  {:ok, valor}
end

Esto permite que el compilador razone sobre qué ramas de un case son alcanzables, qué patrones nunca van a hacer match, y qué funciones reciben argumentos de tipo incorrecto.

El protocolo de diagnósticos de LSP

Otra novedad importante de 1.18 es la integración con el Language Server Protocol a través de un sistema de diagnósticos mejorado. Elixir LS y Lexical (los dos servidores de lenguaje más usados) pueden ahora mostrar en tu editor los warnings del compilador con posiciones de código mucho más precisas.

Si usas VS Code, Neovim o cualquier editor con soporte LSP, los errores de tipo aparecen subrayados en línea mientras escribes, sin necesidad de correr mix compile manualmente.

Qué cambia en el día a día con 1.18

Para proyectos existentes, la migración es transparente. No tienes que añadir anotaciones de tipo, no tienes que cambiar nada. Los warnings nuevos aparecen en la salida del compilador y puedes tratarlos como cualquier otro warning: ignorarlos, corregirlos o configurar el nivel de verbosidad.

Donde sí vas a notar una diferencia es en código nuevo. El compilador ahora rechaza patrones que son matemáticamente imposibles:

def ejemplo(x) when is_integer(x) do
  case x do
    x when is_binary(x) -> "nunca ocurre"  # warning: cláusula inalcanzable
    _ -> "ok"
  end
end

Antes este código compilaba sin queja. Ahora recibes un aviso de que la primera cláusula del case no puede ejecutarse nunca, porque x ya es un entero por el guard de la función.

Mix y Hex: el ecosistema de herramientas

Más allá de los tipos, el ecosistema de Elixir sigue madurando. Mix, la herramienta de build, gestiona proyectos, dependencias, tareas y releases. Hex, el gestor de paquetes en hex.pm, aloja tanto librerías de Elixir como de Erlang puro, lo que da acceso a décadas de código battle-tested.

# Crear un proyecto nuevo
mix new mi_proyecto --sup

# Instalar dependencias
mix deps.get

# Correr los tests
mix test

# Compilar con warnings detallados
mix compile --warnings-as-errors

La flag --sup crea el proyecto con un árbol de supervisión OTP ya configurado, algo que en la práctica querrás casi siempre.

Hacia dónde va Elixir

El roadmap de tipos es largo. La 1.18 es solo el comienzo: inferencia básica y warnings. Las versiones siguientes irán añadiendo tipos para structs, para protocolos, para funciones de orden superior. El objetivo a medio plazo no es convertir Elixir en un lenguaje estático, sino darte la opción de añadir tanta o tan poca información de tipos como quieras, y que el compilador use lo que hay para ayudarte.

Si vienes de Rust (donde el sistema de tipos es el núcleo del lenguaje) o de Go (donde es más sencillo pero igualmente estático), el enfoque gradual de Elixir puede parecer tímido. Pero tiene sentido para un lenguaje donde el código en producción cambia en caliente y donde recargar un módulo sin reiniciar el sistema es una operación normal. Puedes ver cómo otros lenguajes han resuelto problemas similares de concurrencia en el artículo sobre goroutines y channels en Go.

Para los que ya usan Elixir, 1.18 es una razón para revisar el código legacy y dejar que el compilador encuentre cosas que antes pasaban desapercibidas. Para los que están empezando, es un buen momento para entrar: el lenguaje tiene más herramientas que nunca y la curva de aprendizaje se vuelve menos empinada cuando el compilador te dice qué está mal.

Los demás artículos de esta serie cubren OTP, Phoenix LiveView, Ecto y todo lo que necesitas para construir con Elixir en serio. Si te interesa el mundo de los sistemas fiables y la concurrencia, este lenguaje merece mucho más atención de la que suele recibir.

Imagen: Pexels / Myburgh Roux

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP