- La versión Elixir 1.19 permite detectar más errores con mayor rapidez gracias al fortalecimiento del sistema de tipos y a mejoras en el rendimiento de compilación
- La inferencia de tipos se amplía a funciones anónimas y protocolos, lo que habilita una validación automática más amplia incluso sin anotaciones de tipo del usuario
- En proyectos grandes ofrece hasta 4 veces más velocidad de compilación, e incluye optimizaciones de compilación en paralelo y carga de código
- También se refuerzan el ecosistema y la transparencia de la cadena de suministro con soporte para Erlang/OTP 28 y la adopción de certificación OpenChain
- Además, incluye varias funciones como mejoras en el análisis de opciones, mayor capacidad de depuración en ExUnit y mejor accesibilidad a la documentación basada en shell
Principales mejoras de Elixir 1.19
Mejoras en el sistema de tipos
Inferencia de tipos en todos los componentes
- Type inference (inferencia de tipos) es una función que determina automáticamente el tipo de una expresión en tiempo de compilación
- Antes se buscaba dar soporte a la inferencia de tipos principalmente en patrones, guardas y valores de retorno, pero en esta versión se introduce la inferencia de tipos para todos los componentes (excepto las guardas)
- Como la inferencia toma en cuenta también las llamadas a funciones dentro del módulo y a funciones de la biblioteca estándar de Elixir, funciones que antes se inferían como
dynamic() -> boolean() ahora pueden inferirse de forma más precisa, por ejemplo como integer() -> boolean()
- La inferencia de tipos implica varios trade-offs como velocidad de compilación, expresividad, compilación incremental y claridad de errores, por lo que más adelante también se incorporarán inferencia de tipos en guardas e información de tipos de dependencias
- Si una función tiene una firma de tipos explícita, entonces en lugar de inferencia de tipos se aplica una verificación de tipos explícita, que solo permite tipos acordes con las anotaciones del usuario
Verificación de tipos en despacho e implementación de protocolos
- Elixir ahora aplica verificación de tipos al invocar e implementar protocolos
- Por ejemplo, si se pasa a una interpolación de cadenas un tipo que no implementa el protocolo
String.Chars, se mostrará un mensaje de advertencia
- También se generará una advertencia si en una comprensión
for se pasa como generador un tipo que no cumple con el protocolo Enumerable
- Estas verificaciones de tipos permiten prevenir más bugs en tiempo de compilación
Inferencia y verificación de tipos en funciones anónimas
- Elixir 1.19 añade soporte para inferencia y verificación de tipos en funciones anónimas
- Por ejemplo, si a una función anónima que espera un tipo
%{} se le pasa un tipo incorrecto como "hello", esto puede detectarse de inmediato como una advertencia en tiempo de compilación
- La inferencia de tipos también se aplica a capturas de funciones (como
&String.to_integer/1), con lo que se amplía el alcance de la validación automática de tipos
Referencias y socios
- Este sistema de tipos fue desarrollado mediante una alianza entre CNRS y Remote
- Fresha, *Starfish* *, Dashbit y otros brindaron apoyo
Mayor velocidad de compilación en proyectos grandes
Mejora de cuellos de botella en la carga de código
- Antes, los módulos se cargaban inmediatamente al definirse, pero en esta versión se cambió a una estrategia de lazy loading (carga diferida)
- Gracias a esto, se reduce la carga sobre el servidor de código y mejora el rendimiento de la compilación en paralelo, lo que eleva la velocidad de compilación en proyectos grandes a más del doble
- Dos puntos importantes a tener en cuenta
- Si durante la compilación se crea un proceso separado y este intenta acceder a módulos dentro del mismo proyecto, puede ocurrir que falte la carga; para evitarlo se usan
Kernel.ParallelCompiler.pmap/2 o Code.ensure_compiled!/1, entre otros
- Dentro del callback
@on_load, al invocar módulos del mismo proyecto pueden producirse errores; si es necesario, se puede usar la opción @compile {:autoload, true}
- En ambos casos antes podían producirse errores de compilación no deterministas, pero con esta mejora ahora se garantiza un entorno de compilación determinista (reproducible)
Compilación paralela de dependencias
- Se da soporte a la compilación paralela de dependencias (dependencies) mediante la variable de entorno
MIX_OS_DEPS_COMPILE_PARTITION_COUNT
- Como las dependencias se compilan en paralelo aprovechando varios procesos del sistema operativo al mismo tiempo, el rendimiento de compilación puede mejorar hasta 4 veces, según el tamaño del proyecto y la cantidad de núcleos de CPU
- De forma experimental, configurar un valor equivalente a aproximadamente la mitad del total de núcleos resulta efectivo para el uso de recursos
- Como la paralelización puede aumentar el uso de memoria, se requiere precaución al aplicarla en CI o en servidores de build
Soporte para Erlang/OTP 28
- Elixir 1.19 soporta oficialmente Erlang/OTP 28.1+
- Debido a cambios en la representación de expresiones regulares en Erlang/OTP 28, ya no es posible usar expresiones regulares como valor por defecto de un struct
- Al inicializar un struct, sí sigue siendo posible usar expresiones regulares
Adopción de certificación OpenChain
- Esta versión es la primera en comenzar a cumplir con la especificación OpenChain
- Cada release incluye un SBoM (Source Bill of Materials) en formatos CycloneDX 1.6/SPDX 2.3
- Esto mejora la transparencia de la cadena de suministro de los componentes y licencias del release, y contribuye a una gestión más estricta
- Este trabajo fue realizado por Jonatan Männchen y patrocinado por la Erlang Ecosystem Foundation
Otras mejoras
- Se añadieron diversas mejoras en herramientas y bibliotecas, como análisis de opciones, depuración y rendimiento de ExUnit, y accesibilidad a documentación basada en shell
- Para notas de versión más detalladas, consulta el CHANGELOG
1 comentarios
Comentarios de Hacker News
Se destaca que la forma en que Elixir está introduciendo gradualmente el chequeo automático de tipos es un excelente ejemplo de mejora de lenguaje del que otros lenguajes de programación podrían aprender; ha habido muchos casos en los que grandes cambios dividieron al ecosistema en dos, y da tranquilidad que José haya dejado claro desde 2018 que el lenguaje en sí ya está completo. Explica que el lenguaje y el core ya no se van a romper, lo que da mucha estabilidad, y recomienda la charla relacionada. Le impresiona una gestión tan consistente y bien llevada.
Elixir sigue lanzando grandes funciones y mejoras de forma constante, y avanza con estabilidad. La estructura del lenguaje es excelente y sus creadores siguen marcando una dirección correcta de forma continua, lo cual resulta realmente impresionante. Más bien da pena no tener oportunidades cotidianas para usar Elixir.
Comparte datos experimentales sobre la velocidad de compilación de dependencias en Phoenix. En una app pequeña con solo las dependencias básicas de Phoenix, en una Mac M1 Max, se midieron los siguientes tiempos de compilación según el valor de la variable de entorno
MIX_OS_DEPS_COMPILE_PARTITION_COUNT:Entre cada prueba borró la caché con el comando
rm -rf _build.dep, por lo que no quedaron rastros en_build.En los últimos meses llegó a gustarle mucho Gleam. También le alegra la introducción del sistema de tipos en Elixir, pero antes este punto era uno de los principales factores que le dificultaban adoptar Elixir. Le gustaría volver a intentarlo algún día, aunque le preocupa que termine siendo como TypeScript en JavaScript: tipado solo en apariencia, mientras que en muchas libs o paquetes todo acaba siendo dynamic/any. Se pregunta si esa preocupación será infundada. BEAM es realmente excelente.
Siente que Elixir es el entorno de desarrollo web más prometedor. Cada vez que se encuentra con organizaciones o equipos que usan Elixir en el trabajo real, le parece que su nivel suele ser más alto que el promedio. Cree que, en contextos donde se necesita desarrollo continuo, Elixir sigue marcando dirección y estándares.
Presenta que este release de Elixir empezó a dar soporte a formatos Source SBoM como CycloneDX 1.6 o superior y SPDX 2.3 o superior. Es algo realmente de agradecer que la gestión de SBOM se haga a nivel del lenguaje. Lamentablemente, en su empresa actual no usan Elixir.
Si alguien quiere contribuir a un proyecto open source de Elixir usado de verdad, comenta que componentes principales del antiguo Mozilla Hubs siguen desarrollándose en Elixir como proyectos independientes. Recomienda ver Hubs Foundation/reticulum.
Basándose en la biblioteca estándar de Elixir, es posible hacer inferencia de tipos en tiempo de compilación para situaciones específicas de la app, como booleanos dentro de tipos dinámicos o booleanos a partir de enteros.
No tiene experiencia desarrollando con Elixir, pero es fan. Antes le gustaban la practicidad y la belleza de Ruby, pero cambió de lenguaje al sentirse atraído por los sistemas de tipos. Tanto Elixir como Ruby introdujeron sistemas de tipos, pero ahora usa principalmente Kotlin, que sintácticamente se siente como un “Ruby tipado”.
Está usando Soketi con el sdk de pusher para manejar broadcast de eventos. La app tiene una estructura mixta con endpoints en tiempo real y endpoints REST, y la carga de cómputo en tiempo real no es tan alta, aunque si hace falta piensa manejarla por separado con Go. También planea agregar funciones de colaboración pronto, y se pregunta si en una situación así tiene sentido adoptar Phoenix.