Elixir v1.20: ahora un lenguaje con tipado gradual
(elixir-lang.org)- La inferencia de tipos y la verificación gradual (gradually) de tipos se aplican a todos los programas de Elixir, lo que permite encontrar bugs verificados que llevarían a código muerto y fallos garantizados en tiempo de ejecución, incluso sin anotaciones de tipo
- El tipo
dynamic(), a diferencia deany()que “permite cualquier cosa”, rastrea el rango de tipos posibles en tiempo de ejecución y solo reporta una infracción cuando no hay superposición total con los tipos permitidos - Un valor
dynamic(integer() or binary())no genera una infracción en llamadas donde algunas posibilidades se superponen, como operaciones numéricas o funciones de cadenas, pero sí la genera en llamadas que solo aceptan map, comoMap.fetch! dynamic()se va acotando según cómo se use, refinandodataen código comodata.a + data.bhacia un map con la forma%{..., a: number(), b: number()}- En los guards, infiere unión, intersección y negación para usar como información de tipos condiciones como
is_list,is_integer,is_map_key,not is_map_keyytuple_size casey las condicionales reflejan la información de cláusulas anteriores en las siguientes, realizando verificaciones de tipos como manejar primeronily luego acotar el valor restante abinary()- Se añadieron tipos a varias funciones relacionadas con tuple y map en la biblioteca estándar, lo que ayuda a encontrar cláusulas redundantes y código muerto en bases de código existentes
- En “If T: Benchmark for Type Narrowing”, superó 12 de 13 categorías, mostrando que puede recuperar información de tipos precisa en código Elixir común
- v1.20 también volvió a mejorar los tiempos de compilación en aplicaciones para entornos multinúcleo, y en benchmarks sintéticos la herramienta de build de Elixir mostró los resultados más rápidos entre los lenguajes de BEAM
- La nueva opción del compilador
:module_definitionpermite elegir el modo de ejecución de la definición de módulos entre el valor predeterminado:compiledo:interpreted, y se activa conelixirc_options: [module_definition: :interpreted]enmix.exs - La opción
:module_definitionno afecta a los archivos.beamescritos en disco y solo cambia la forma de ejecución dentro dedefmodule, por lo que puede ayudar a mejorar los tiempos de compilación en proyectos grandes - Las nuevas firmas de tipos que aprovechan tipos conjuntistas se discutirán junto con la definición de typed struct después de que se cumplan las investigaciones sobre rendimiento del sistema de tipos de v1.20, tipos recursivos, tipos parametrizados y recorrido de pares clave-valor en map
1 comentarios
Comentarios de Hacker News
Puede que sea solo mi experiencia personal, pero siento que, si no es un lenguaje que tuvo tipos desde el principio, no funciona tan bien como un verdadero lenguaje de tipos estáticos
Llevo unos 10 años trabajando como desarrollador profesional de Elixir y desde hace mucho esperaba la llegada de los tipos. Me alegra muchísimo que por fin haya entrado ese primer paso en esta ocasión
Aun así, me gustaría saber cómo se compara el estado incluido en v1.20 con Dialyzer sin especificaciones. Entendía que el enfoque de success typing de Dialyzer se parece más a “si existe хотя бы una combinación de argumentos que funcione, no avisa”, en vez de “avisa si hay una combinación de argumentos que puede fallar”, y pensé que lo que Elixir estaba haciendo aquí era parecido, pero nunca sentí que Dialyzer fuera especialmente útil
He visto varias veces en HN artículos sobre el sistema de tipos graduales de Elixir, pero no los he seguido a detalle. Me pregunto si alguien sabe si este sistema de tipos graduales puede cambiar la complejidad asintótica de un programa en comparación con código sin tipos
Hasta donde sé, la mayoría de los sistemas de tipos graduales, por ejemplo Racket, pueden hacer que un programa sea asintóticamente más lento, aunque hay algunas excepciones [1]
[1] https://doi.org/10.1145/3314221.3314627
La mayoría de los sistemas de tipos graduales insertan coerciones cuando un valor cruza la frontera entre código tipado y no tipado. Por ejemplo, revisan todos los elementos de una lista o envuelven un valor en un proxy de tipos. Pero el equipo de Elixir publicó resultados de strong arrows para obtener solidez sin esas verificaciones en tiempo de ejecución, y el bytecode que genera el compilador es semánticamente idéntico al del código sin tipos
Irónicamente, los críticos decían que hacían falta tipos, y los fans de Elixir decían que no hacían falta y que Elixir era de algún modo mágico, así que no tenía bugs relacionados con tipos. Ahora que le están metiendo tipos, está encontrando bugs. ¿No se suponía que no hacían falta para prevenir bugs? Aun así, es un buen cambio. En su momento usé bastante Elixir y me gustó, pero me costaba aceptar la ausencia de tipos
https://en.wiktionary.org/wiki/Goomba_fallacy
No estoy de acuerdo con esa postura, pero es una afirmación mucho más defendible que decir “$LANGUAGE es magia”
Antes del avance de la teoría de tipos conjuntista, esa postura quizá sí era correcta
Y al final terminan agregando tipos estáticos. Pasó con Python, JavaScript y Ruby, y seguramente con más
Me encanta poder actualizar Elixir sin que haya cambios incompatibles en varios proyectos, y que el compilador me encuentre bugs gratis. Ya me malacostumbré
Esto de verdad me da mucho gusto. Ya se está acercando al nivel de “gran lenguaje”, y para mí Elixir es el primer candidato
Si conocen otro lenguaje que ya sea cómodo de usar y al mismo tiempo siga agregando grandes funcionalidades de forma estable y segura, me encantaría saberlo. Después de dominar Go me pasé a aprender C# avanzado, porque sentía que Go se había quedado estancado en cuanto a sumar buenas funcionalidades
En el último mes hice el track de Elixir en exercism.io https://exercism.org/tracks/elixir
Es realmente excelente
Ah, ahí vamos otra vez. Parece que voy a pasar otro año aprendiendo Elixir de nuevo
Me encanta todo de Elixir, pero más que cualquier otro lenguaje, Elixir hace que siga dudando de mí mismo. Siento que mi cerebro no está hecho para lo funcional, pero este cambio me dan ganas de intentarlo otra vez
Lo malo es que no diría que el ecosistema sea muy amigable para principiantes, y muchas veces, cuando responden preguntas, asumen que ya conoces bastante el lenguaje
No se dejen engañar por el título. La primera mitad del libro es simplemente Elixir
He usado este libro cada vez que volví a adaptarme a Elixir durante los últimos 8 años, y siempre me ha funcionado. Nunca lo he terminado
Uno de mis criterios para saber si este tipo de libros de programación basados en proyectos y tutoriales es bueno, es si aunque lo empiece varias veces y no llegue al final, ya a la mitad me da las herramientas para irme a hacer mi trabajo
Pero creo que no es tanto que tu cerebro no encaje, sino el contraste entre el nivel de experiencia que traes de lenguajes imperativos y el hecho de volver a empezar como principiante en un estilo puramente funcional
Va a ir mejorando. El momento en que la programación funcional empezó a resultarme cómoda fue cuando me di cuenta de cuánto me gusta encadenar código tipo “one-liners” de Bash con bastante espacio. Si los datos empiezan con cierta forma, los vuelco con un comando, pienso en la etapa que los acerca más a la forma que quiero, los paso por pipe al siguiente comando y vuelvo a mirar. Si sigues así, al final normalmente te queda una secuencia de transformaciones de datos que no mutan nada
Una razón por la que esto se siente cómodo en el shell es que todos los días andas recorriendo el sistema de archivos y acumulando vocabulario de comandos. Tu biblioteca familiar de “funciones” en un entorno tipo Unix se vuelve bastante grande con los años. En un entorno de programación puramente funcional hay que hacer lo mismo, pero aprender el vocabulario cuesta un poco más de esfuerzo. Tus “comandos” más frecuentes pasan a ser funciones como
map,fold,zipen vez de grep, cat o sortPero en el fondo es realmente lo mismo, y el atractivo de construir pipelines aplica igual en ambos lados. Puedes armarlo por partes, y en cada pequeño rompecabezas puedes olvidarte del paso anterior y pensar solo en cómo transformar los datos que tienes enfrente al siguiente estado. Esa baja carga de contexto se siente fresca y cómoda
Ojalá lo intentes y lo disfrutes. Cuando logras disfrutar el hecho de no poder hacer algo todavía, es cuando por fin empiezas a volverte bueno
Claro, solo le dediqué unas cuantas tardes, pero si fuera a reentrenar mi cerebro para lo funcional otra vez, probablemente elegiría Gleam por esa familiaridad
A veces hay publicaciones ambiguas que no reciben atención, o las ignoran porque huelen a “háganme la tarea”
Pero, por lo que yo he visto, todas las publicaciones con curiosidad genuina reciben respuesta
Excelente. En 1.20 parece que la compilación de nuestra gran app umbrella se volvió bastante más rápida
Me pregunto cómo se compara con Gleam. O más bien, ¿por qué usar Elixir ahora en vez de Gleam? Phoenix, y en particular LiveView, sí parecen ser una gran ventaja de Elixir
No sé cuál sea el estado actual de Gleam OTP, pero la última vez que lo vi no estaba muy bien
Si te da igual todo eso y solo te importan los tipos, entonces usa Gleam. Aunque en ese caso, ¿por qué no usar simplemente Rust?
Por ejemplo, en Gleam el JSON decoding/encoding puede volverse verboso. En Rust basta con derivar serde, y en Elixir basta con una llamada a función
Elixir tiene un ecosistema más maduro. Por ejemplo, en Gleam puedes usar Phoenix u otros frameworks de Gleam, pero la experiencia no es la misma
La gran razón por la que Gleam resulta más atractivo que Elixir son los tipos, y ahora Elixir está empezando a cerrar esa brecha. También está el hecho de que puede compilar a JavaScript, y en Elixir Hologram está haciendo algo parecido
Personalmente, me gusta más el sistema de tipos de Gleam y su sintaxis tipo Rust, pero hoy por hoy siento que Elixir es una mejor opción para todos mis proyectos de desarrollo web