Cómo va nuestra reescritura de Rust a Zig
Un artículo extenso sobre la reescritura del compilador del lenguaje Roc de Rust a Zig ha impulsado un examen más amplio de las concesiones entre seguridad, rendimiento y tooling en los lenguajes de sistemas. Los comentaristas contrastan las fuertes garantías estáticas y el ecosistema maduro de Rust con las compilaciones incrementales extremadamente rápidas de Zig, su control de memoria de grano fino y su inestabilidad pre‑1.0, debatiendo si siquiera es viable añadir a Zig un borrow checking similar al de Rust. El hilo también profundiza en cuánta “seguridad de memoria” pueden ofrecer realisticamente los compiladores y runtimes, el papel de la recolección de basura y los schedulers en lenguajes como Go, y cuándo está justificado aceptar más código `unsafe` a cambio de rendimiento o ergonomía.
Rust vs Zig para la implementación de compiladores
- Muchos coinciden en que las compilaciones incrementales de Zig (p. ej., reconstrucciones de ~35 ms) son un gran atractivo para el trabajo en compiladores; Rust se percibe como más lento, aunque está mejorando, con una hoja de ruta oficial para compilaciones más rápidas.
- Algunos señalan que en el compilador actual de Roc, las compilaciones completas todavía pueden ser más lentas en Zig que en Rust; otros enfatizan que la arquitectura de Zig está optimizada para el rendimiento futuro.
- Varios sostienen que la elección del lenguaje importa menos que los algoritmos y las estructuras de datos, aunque otros replican que el control de bajo nivel sobre memoria/disposición puede producir mejoras de un orden de magnitud una vez que los algoritmos están fijados.
Seguridad de memoria, unsafe y borrow checking
- Fuerte debate sobre si añadir a Zig un borrow checker al estilo de Rust (mediante análisis estático o herramientas de IR) es viable:
- Un lado: “imposible” o muy poco ergonómico sin diseño de lenguaje consciente de lifetimes, traits, encapsulación y expresividad restringida.
- El otro lado: cita herramientas, analizadores personalizados y ejemplos (Ada/SPARK, proyectos tipo Oxide) como evidencia de que una seguridad adicional puede “añadirse encima”, aunque con coste y falsos positivos.
- Discusión sobre límites fundamentales: el análisis de aliasing y de seguridad temporal se vuelve indecidible en general; Rust resuelve esto restringiendo la expresividad (propiedad afín/lineal).
- El modo ReleaseSafe de Zig y los allocators de depuración ofrecen comprobaciones de límites, detección de fugas, detección de double-free / cierta detección de UaF usando direcciones no reutilizadas, pero no una seguridad temporal completa.
- Muchos subrayan que “memory safe” en Rust es una garantía específica y limitada; el Rust seguro aún puede generar código incorrecto o ser inseguro debido a errores del compilador (p. ej., CVEs teóricas).
Qué significa “seguridad” y dónde encajan los compiladores
- Larga subdiscusión que distingue entre:
- Seguridad de memoria (objetiva, formalizable).
- “Seguridad” en sentido amplio (dependiente del contexto: seguridad, corrección, seguridad humana).
- Algunos argumentan que la seguridad es una propiedad del sistema, no del lenguaje; un compilador seguro aún puede emitir binarios vulnerables.
- Otros replican que las garantías a nivel de componente siguen siendo valiosas: reducir la superficie
unsafehace más manejables la depuración, el sandboxing y los límites de confianza. - Debate sobre si los compiladores son “sensibles a la seguridad”:
- Una postura: los compiladores no están endurecidos contra entradas maliciosas (p. ej., el modelo declarado de LLVM); el UB en compiladores es “solo otro bug”.
- Postura opuesta: los compiladores son raíces críticas de confianza; los exploits de memoria en ellos pueden inyectar código en todos los binarios derivados.
Runtime y planificación de Go
- Un comentarista afirma que el scheduler de Go es “el más sofisticado del mundo” y puede superar a Rust en throughput al intercambiar memoria por concurrencia.
- Varias respuestas cuestionan esto por exagerado y poco consistente con la experiencia y los benchmarks, señalando sistemas de alto rendimiento que terminan optimizando la memoria manualmente de todos modos.
- Otros mencionan runtimes competidores (JVM, CLR, Erlang) y que la teoría de scheduling es profunda; la afirmación se considera en general no sustentada.
Tiempos de compilación, cachés y tooling
- Las compilaciones lentas de Rust y los grandes directorios de artefactos son una queja recurrente; algunos proyectos ven compilaciones incrementales de varios minutos debido al uso intensivo de genéricos y macros/generación de código (p. ej., algunas pilas GraphQL).
- Sugerencias:
- Usar directorios
targetcompartidos/globales y herramientas como sccache. - El equipo de Cargo está rediseñando el diseño de artefactos para habilitar recolección de basura y mejor gestión de caché.
- Usar directorios
- El equipo de Zig explica que, para ediciones pequeñas, el coste de la reconstrucción incremental está dominado por el recorrido del grafo de dependencias y la detección de cambios, no por la generación de código, así que el rendimiento debería ser similar entre arquitecturas.
Madurez de Zig, cambios incompatibles y “listo para producción”
- Tensión en torno al estado pre‑1.0 de Zig:
- Defensores: en la práctica está “listo para producción”; la etiqueta pre‑1.0 principalmente preserva la libertad de hacer cambios incompatibles frecuentes. Se citan usuarios de producción exitosos.
- Críticos: los cambios incompatibles frecuentes en el núcleo (p. ej., APIs de E/S) hacen que no esté listo para la mayoría de los equipos de producción; argumentan a favor de semver o esquemas de edición adecuados en lugar de una ruptura abierta.
- Algunos prefieren el enfoque de Zig (volatilidad honesta) frente a lenguajes conservadores y de acumulación pesada; otros insisten en la estabilidad a largo plazo para despliegues serios.
Elección de lenguaje, GC y rendimiento
- Discusión sobre OCaml y otros lenguajes gestionados/FP para compiladores: históricamente exitosos, existen compiladores muy rápidos; algunos creen que la suposición de Roc de “debe ser un lenguaje de sistemas” es demasiado fuerte.
- Contraargumento: las CPUs modernas y las características del lenguaje (p. ej., asignación sofisticada de closures) cambian las restricciones; el control fino sobre la disposición y la asignación puede importar mucho.
- Debate más amplio sobre GC:
- Algunos sostienen que el rechazo al GC está exagerado y que la mayoría de los servicios reales podrían tolerar GCs modernos.
- Otros describen sistemas de alto throughput / baja latencia donde los parones de escala de µs importan y las pausas del GC (incluso las de “baja latencia”) son inaceptables, así que el GC queda descartado.
Reacciones al lenguaje Roc y preguntas abiertas
- Varios comentaristas encuentran Roc interesante pero no están seguros de su nicho objetivo y casos de uso (scripting, plugins frente a lenguaje para apps servidor/cliente; competencia frente a WASM, Gleam, Elm).
- A algunos les gustan el pattern matching de Roc y los patrones de cadenas sin asignación, pero señalan un bug sutil en un ejemplo de enrutamiento y se preocupan por semánticas delicadas con barras diagonales incrustadas.
- Comentario menor sobre estilo: las líneas separadas de anotación de tipos resultan incómodas para algunos en comparación con la sintaxis al estilo F#.
Cultura, reescrituras y subhilos de AI/Bun
- Algunos ven surgir una ola de ruido de “reescribir Rust a X” y advierten contra el tribalismo de lenguajes; otros enfatizan el “herramienta adecuada para el trabajo” y aceptan reescrituras cuando cambia la adecuación al dominio.
- Una comparación breve con la reescritura de otro proyecto de Zig a Rust provoca bromas sobre un “UNO reverse”, pero también plantea preguntas sobre la sostenibilidad a largo plazo de ecosistemas pre‑1.0.
- Un hilo pregunta por qué una gran empresa de IA adquirió un proveedor de runtime de JavaScript en lugar de simplemente hacer un port; las respuestas se centran en el riesgo de fracaso de una startup, el control estratégico y las motivaciones de acquihire.