- La lógica de resolución de tipos (type resolution) del compilador de Zig fue rediseñada por completo, simplificando su estructura interna y aportando mejoras visibles para los usuarios
- El nuevo diseño procesa de forma perezosa (lazy) el análisis de campos de tipos, por lo que evita inspeccionar innecesariamente la estructura detallada de tipos no inicializados
- Los mensajes de error de bucles de dependencias (dependency loop) mejoraron de forma concreta, permitiendo identificar con claridad la causa del ciclo
- Se resolvieron el problema de análisis excesivo en la compilación incremental (incremental compilation) y numerosos bugs, lo que mejora notablemente la velocidad de compilación
- Este cambio incluye decenas de correcciones de bugs y pequeñas mejoras del lenguaje, reforzando en general el rendimiento y la experiencia de desarrollo del compilador de Zig
Rediseño de la lógica de resolución de tipos
- Se fusionó un PR de unas 30 mil líneas, reescribiendo la lógica de resolución de tipos del compilador de Zig con una estructura más lógica e intuitiva
- En este proceso se ordenó la estructura interna del compilador, con mejoras directas también para los usuarios
- El compilador ahora evalúa de forma diferida el análisis de campos de tipos, evitando explorar innecesariamente la estructura detallada de tipos no inicializados
- En el código de ejemplo, si una estructura que incluye un campo
@compileError se usa solo como namespace, antes se producía un error de compilación, pero ahora compila correctamente
- Esto evita dependencias de código innecesarias al usar tipos con forma de namespace como
std.Io.Writer
Mejora de los mensajes de error de bucles de dependencias
- Antes, los mensajes de error de bucles de dependencias eran ambiguos, pero ahora muestran con claridad la causa y la ubicación del ciclo
- En el código de ejemplo, cuando las estructuras
Foo y Bar se refieren entre sí, el mensaje de error señala de forma específica dónde depende cada tipo del otro
- El mensaje incluye la longitud del ciclo, la ubicación de la declaración de cada campo y la ubicación de la consulta de alineación
- Incluso en ciclos complejos, se proporciona suficiente información para identificar fácilmente la causa del problema
Mejora de rendimiento en la compilación incremental
- Con este cambio se corrigieron numerosos bugs de la compilación incremental
- En particular, se resolvió el problema de análisis excesivo (over-analysis), optimizando la recompilación para que solo se vuelvan a compilar las partes modificadas
- Como resultado, en muchos casos la velocidad de compilación mejora notablemente
- Los desarrolladores pueden activar la compilación incremental en Zig 0.15.1 o superior para probar esta experiencia de desarrollo mejorada
Otras mejoras
- Este PR incluye decenas de correcciones de bugs, pequeños cambios del lenguaje y mejoras de rendimiento del compilador
- La mayoría corresponde a detalles o casos especiales
- El historial completo de cambios puede consultarse en PR #31403 en Codeberg
- Se recomienda reportar issues si se descubren nuevos bugs
Importancia del cambio
- La simplificación de la lógica de resolución de tipos y la optimización de la compilación incremental refuerzan la estabilidad y eficiencia del compilador de Zig
- Los desarrolladores reciben retroalimentación más rápida y clara, y pueden esperar mayor productividad incluso en bases de código grandes
1 comentarios
Comentarios en Hacker News
Soy el autor de este devlog
Entiendo la preocupación por las rupturas de compatibilidad causadas por cambios en el lenguaje, pero quiero aclarar que este cambio del compilador no es de una magnitud que vaya a causar un impacto grande
Por ejemplo, al compilar ZLS con la nueva rama, solo hizo falta cambiar
.{}por.empty. Esto se debe a la eliminación del valor por defecto destd.ArrayList, que ya llevaba 1 año en estado deprecatedTambién en el caso del proyecto Awebo, solo hubo tres cosas que corregir en todo el árbol de dependencias: el cambio a
.empty, agregarcomptimey agregarorelse @alignOf(T)La mayoría de estos cambios son lo bastante simples como para que la mayoría de los desarrolladores de Zig los resuelvan casi en automático
El punto central de este PR no es tanto la ruptura, sino la corrección de bugs y la mejora de la compilación incremental
Creo que la calidad y la planificación del PR son muy altas, y nunca tuve la intención de menospreciar el esfuerzo del autor
Más bien, me quedó la lección de que en adelante debería comentar más y dejar opiniones con más cuidado
lib/std/multi_array_list.zigme surgió una dudaNo entiendo por qué usar
@alignOf(T)en la definición deMultiArrayList(T)genera una dependencia circularIncluso si
TfueraMultiArrayListen sí, ¿no sería un tipo monomórfico completamente distinto? Siento que se me está escapando algoCódigo relacionado: enlace
Tengo curiosidad por la experiencia de quienes usan Zig en producción
Como el lenguaje cambia seguido, me interesa saber cómo manejan los ciclos de actualización o de reescritura, y si pasa que los paquetes de dependencias se quedan atrás respecto a la versión del lenguaje
Sé que Bun aprovecha bien Zig, pero me gustaría escuchar otros casos
Durante los últimos 1 o 2 años, los cambios del lenguaje y de la librería estándar han avanzado sin mayores problemas
Antes las actualizaciones eran molestas, pero ahora se sienten más como una pequeña incomodidad
Si me preguntaran por la experiencia de usar Zig, este aspecto es tan estable que casi ni lo mencionaría
Este tipo de proyectos grandes actualizan tomando como base releases etiquetados, y normalmente completan la migración en unos días o unas semanas
Además casi no tienen dependencias, así que el costo de actualizar no es alto
Eso sí, a veces un error tipográfico menor provoca un crash del compilador con SIGBUS, lo que vuelve difícil depurar
.zig-cachellegó a crecer hasta 173GB, y eso también causó problemas en un VPS ARMSubir
lightpandade 0.14 a 0.15 fue bastante tranquilo. No creo que 0.16 traiga grandes problemas tampocoPero como desarrollador de librerías, sí cuesta seguir el ritmo de cambios rápidos de 0.16
Por ahora solo lo estoy manejando experimentalmente en la rama “dev”
Reescribí un módulo de Node.js/TypeScript en Zig, y quedó 2 veces más rápido y con 70% menos uso de memoria
El soporte de Zig para serialización de
sqlite/JSONfue una gran ventajaEl lado negativo es que, por la ausencia de sintaxis para closures o vtables, cuesta más separar capas en el código
Con
Arcsy un allocator tipo bumper logré mantener la seguridad de memoria, y pienso seguir operándolo en modo DebugSafeAl pasar a ReleaseFast sí hubo una mejora de 25% en velocidad, pero no lo suficiente como para compensar la pérdida de seguridad
Aunque haya que modificar código, a largo plazo sigue siendo el enfoque correcto
Me ha impresionado lo que ha logrado el equipo de Zig
Uso seguido la terminal ghostty hecha en Zig, y es muy estable
Aun así, personalmente prefiero Rust
Rust adopta un modelo de “mundo cerrado”, mientras que Zig adopta uno de “mundo abierto”
En Rust hay que implementar explícitamente un trait, pero en Zig basta con que la forma (shape) del tipo coincida para que funcione
Gracias a eso, Zig permite una metaprogramación muy potente, pero también tiene la desventaja de que la inferencia de tipos es menos clara y eso complica el autocompletado, la documentación y el soporte de LSP
Por cómo lo explicas, suena parecido a las interfaces de Go, pero tengo entendido que Zig no tiene un concepto equivalente directo
Me pareció interesante la transición de
kernel32aNtdllEs una idea que también podría aplicarse a la API de espacio de usuario de Linux
En particular, el manejo de errores en la frontera kernel-usuario es similar
Eso sí, en Linux libc y el kernel están muy entrelazados, así que usar
errnoes imprescindibleMe da curiosidad por qué en Windows terminó apareciendo un patrón de este tipo
errnooGetLastError()son herencia de la era anterior a los hilosAntes, con scheduling cooperativo, una variable global era segura, pero cuando llegaron los multicore y los hilos eso se volvió peligroso
Por eso apareció thread local como alternativa
En vez de usar tipos como si fueran namespaces, me pregunto si no sería mejor agregar namespaces explícitos al lenguaje
La idea es agregar una funcionalidad solo cuando sea algo que optimice varias partes a la vez
En Zig,
@importconvierte un archivo en una struct, y los namespaces simplemente se representan como struct anidadasEs decir, un namespace no es más que otro import
(Todavía no me entra bien el café, así que no garantizo precisión total)
Hay algo que a menudo se pasa por alto en las discusiones sobre cambios de lenguaje: el impacto en el ecosistema
Si el lenguaje rompe compatibilidad seguido, no solo las apps sino también librerías, herramientas y tutoriales tienen que seguirle el paso constantemente
Al final, eso inclina el ecosistema hacia proyectos mantenidos activamente, más que hacia librerías de “se hizo una vez y se dejó ahí”
Ese puede ser un tradeoff razonable en la etapa inicial de diseño de un lenguaje, pero a largo plazo sí afecta el crecimiento del ecosistema
Otros lenguajes nuevos están invirtiendo mucho esfuerzo en minimizar esta fatiga por cambios
También será interesante ver qué resultados trae el enfoque de Zig
Blender rompe la API con frecuencia, pero la mayoría de los cambios son menores
Aun así, alguien tiene que arreglarlos, y si el mantenimiento se abandona, al usuario le toca parchearlo por su cuenta
Los addons de pago tienen más probabilidad de seguir mantenidos, pero ni así hay garantía
Las librerías sin mantenimiento de todos modos son código malo
En vez de criticar a Zig, mejor dejen de promocionar otros lenguajes (como C3)
Lo que se menciona en el PR de Zig sobre que “Chromium, boringssl, Firefox y Rust llaman a SystemFunction036 de advapi32.dll” no es cierto
Ellos ya usan ProcessPrng, que en Windows 10 en adelante no falla
La base está en este whitepaper de Microsoft
Está diseñado para que las solicitudes de RNG nunca fallen, y si algo falla, el proceso mismo termina
Es decir, no devuelve códigos de error para garantizar números aleatorios de alta calidad
La semántica del lenguaje de Zig parece simple en la superficie, pero sus interacciones son sutiles
Eso me hace pensar que con el tiempo podrían aparecer casos límite complejos, como pasó con las reglas de templates en C++
Un PR de 30 mil líneas es un logro tremendo
Pero me sorprendió que se cambie la semántica del lenguaje, porque es algo muy importante
Entiendo que Zig todavía no llega a 1.0 y que por eso los cambios van rápido, pero expresiones tan casuales como “cambiamos la semántica en esta rama” me descolocaron un poco
Me pregunto si este tipo de cambios grandes forma parte de la cultura propia de Zig o si simplemente yo ya me estoy quedando atrás
La expresión “modern Zig” también me dio risa por la velocidad a la que cambia el lenguaje
El devlog no es un texto de marketing, sino más bien un registro para gente del círculo interno, y Zig todavía no es 1.0
El PR sí incluye suficiente contexto y fundamentos
Si elegiste Zig, en cierto nivel ya aceptaste el riesgo de cambios en el lenguaje
De hecho, pulirlo bien ahora trae más beneficios a largo plazo
(Piensa en herencias imposibles de corregir, como la precedencia de operadores bit a bit en C)
mlugges colaborador principal de Zig y miembro de la Zig FoundationEste cambio busca resolver dependencias circulares y ordenar el sistema de tipos
Las propuestas relacionadas están publicadas en #3257 y #15909
Con esto, la resolución de tipos de Zig queda organizada como un DAG (grafo acíclico dirigido), lo que mejora mucho la estabilidad del compilador
Zig se maneja bajo un modelo BDFN (Benevolent Dictator For Now), y la decisión final la tiene Andrew Kelley
Pero el equipo funciona como una organización sin fines de lucro y pone por delante la confianza de los usuarios y la calidad del lenguaje
En lo personal, trabajar junto a Matthew es un gran honor
Era impecable en lo formal, pero en la práctica terminó siendo un lenguaje caótico