Un lenguaje de programación eficaz y portable es posible con Zig | Fastly
Diseñar un lenguaje de programación totalmente nuevo no es nada fácil: no solo se trata de crear el compilador, definir la biblioteca de serie y establecer compatibilidades con editores y sistemas de compilación; hay que diseñar el lenguaje en sí. También debes decidir si será de carácter imprescindible o funcional, para qué sistemas se va a utilizar o si va a disponer de funciones de metaprogramación.
Zig, que forma parte de nuestra iniciativa de código abierto sin ánimo de lucro, es un lenguaje de programación y una cadena de herramientas de uso general para mantener software en condiciones óptimas que faciliten su reutilización. Es sólido, fácil de usar, y tiene una arquitectura SIMD portable. La decisión de crear un lenguaje «ad hoc» para satisfacer las necesidades del equipo de Zig es fruto de una profunda reflexión. Para descubrir cómo empezó esta aventura, hemos hablado con Loris Cro, miembro del equipo del proyecto Zig.
Hannah: ¿Cómo surge el lenguaje de Zig? ¿Por qué decidiste unirte al proyecto?
Loris: Me gusta bromear sobre cómo empezó todo. En una de las versiones que suelo contar, a Andrew Kelley (creador de Zig) se le encomendó la tarea de limpiar una base de código C++ tan desordenada que la única forma viable de hacerlo era inventando un lenguaje desde cero. Aunque estuvo a cargo de una enorme base de código C++, lo cierto es que empezó a trabajar en Zig por otros motivos, sobre todo porque le interesaba el procesamiento de audio en tiempo real. Finalmente, tras varios años dedicados casi en exclusiva a Zig (¡noches y fines de semana incluidos!), las donaciones que iba recibiendo de la comunidad le permitieron dejar el trabajo que tenía en OkCupid.
Por entonces, yo era Developer Advocate en Redis Labs. Me maravilló comprobar que Zig era muy buena alternativa a C para programar extensiones de Redis y, entre unas cosas y otras, acabé entrando en la comunidad de Zig. Al principio de la pandemia no sabía qué hacer y creé Zig SHOWTIME, una reinterpretación de eventos online destinados a desarrolladores. Poco tiempo después, Andrew puso en marcha la fundación sin ánimo de lucro Zig Software Foundation, a la que me incorporé como vicepresidente de Comunidad.
Hannah: ¿Qué diferencia a Zig de la competencia?
Loris: El objetivo de Zig es sencillo: lograr una eficacia y portabilidad equivalentes (o incluso superiores) a las de C. También pretende corregir las deficiencias y limitaciones que tanto abundan en sus ecosistemas y en los que hay alrededor. Tenemos la ventaja de poder aplicar todo lo aprendido en décadas de programación de sistemas. Además, los intentos de Andrew de corregir algunos de estos problemas se tradujeron en ideas prometedoras, como la ejecución de código en tiempo de compilación. A propósito, no os perdáis la charla de Andrew, «The Road to Zig 1.0», en la que profundiza en las cualidades que definen a Zig.
Además, desde un punto de vista social, Zig es un proyecto creado desde cero que nace sin lastres. La fundación sin ánimo de lucro es viable por sí misma gracias a una combinación equilibrada de donaciones de empresas y de particulares. Asimismo, no hay ninguna gran tecnológica en nuestro consejo de administración y, la verdad, no queremos que eso cambie. Ante un futuro incierto, me gusta recordar algunos hitos que presagiaron el éxito que ha tenido Zig, como la calidad del tiempo de compilación que diseñamos y el liderazgo de Andrew en la fase de desarrollo.
Algunas figuras destacadas comparten nuestra visión. Frank Denis, por ejemplo. Es Software Engineer del equipo OCTO de Fastly; creó libsodium y aportó un conjunto de herramientas de cifrado a la biblioteca de serie de Zig.
Hannah: Las aplicaciones de Zig se ejecutan más rápido que el código en C y, a la vez, ofrecen mejores garantías de seguridad. ¿Por qué?
Loris: Zig es un lenguaje que cuenta con gestión manual de la memoria y carece de tiempo de ejecución. Esto es lo que hace que el rendimiento de los programas de Zig sea comparable al de los programas de C.
Ahora el foco está en los detalles que indican cómo se genera el código máquina, aspecto en el que Zig presenta ventajas decisivas. Por ejemplo, el tiempo de compilación, que otorga genéricos a Zig y permite ir calculando los resultados previamente durante la compilación. En este otro artículo se explica con todo lujo de detalles cómo Zig mejora el rendimiento. En definitiva, suele ser más práctico escribir código eficiente con Zig que con C.
La seguridad de Zig se refleja en varios modos de compilación, que habilitan verificaciones opcionales del tiempo de ejecución en busca de comportamientos no definidos (por ejemplo, errores de código como tratar de leer más allá del final de una matriz). Otro aspecto de la seguridad de Zig es que presenta un sistema de tipos mucho más expresivo, sobre todo en lo relativo a los punteros. En C, muchos errores (y, por tanto, vulnerabilidades de seguridad) se deben a fallos como olvidar comprobar un puntero nulo, convertir un puntero no válido en el tipo equivocado u omitir la finalización de una cadena o una matriz en NULL. Sin embargo, en Zig el sistema de tipos resuelve todos esos problemas. Me podría extender más sobre este tema, pero vayamos a la idea: también en este caso es más práctico programar código seguro con Zig que con C.
Algunos pensarán que el argumento de la practicidad no se sostiene en teoría. Sin embargo, si consideramos las circunstancias que llevan a la comunidad global de desarrolladores a utilizar una herramienta, la practicidad es un factor importantísimo que afecta directamente a la calidad de cualquier biblioteca. Por eso Zig facilita tanto hacer lo correcto.
Hannah: ¿Qué significa la portabilidad para Zig? He leído que con Zig se puede desarrollar una aplicación en Windows y, al mismo tiempo, generar una versión que funcione en Mac, Linux e incluso Compute@Edge —entorno informático sin servidores de Fastly, desarrollado en WebAssembly—, todo ello sin cambiar una sola línea de código. ¿Es eso cierto?
Loris: ¡Ya lo creo! Zig funciona de manera predeterminada como compilador cruzado, incluso para compilar código C y C++. Se trata de una función genial de Zig con la que ya cuentan otros lenguajes de programación, como Go. En cualquier caso, la compilación cruzada, a pesar de sus magníficas ventajas, también requiere cierta planificación: en condiciones normales, tienes que interoperar con el sistema de destino. De hecho, el sistema de compilación y la biblioteca de serie de Zig están diseñados para admitir la mayoría de las plataformas habituales e incluso tienen un mecanismo BYOOS que te permite maximizar la reutilización de código de la biblioteca de serie para plataformas con las que Zig no es compatible oficialmente.
Zig es un lenguaje de programación de uso general, es decir, debe permitirte configurar sin dificultad un sistema Turing completo que siga un modelo parecido al de Von Neumann. Últimamente, dos máquinas virtuales de ese tipo vienen centrando la atención de los desarrolladores: BPF y WebAssembly. Ni que decir tiene que somos compatibles con ambas. Además, Jakub Konka —incorporado recientemente al equipo principal de desarrollo de Zig y muy implicado en el ecosistema WebAssembly— ha añadido compatibilidad con WASI a la biblioteca de serie de Zig. De hecho, también dio una charla sobre este tema.
En cuanto a Compute@Edge de Fastly, quizás te interese echar un vistazo a Zigly. Es una biblioteca elaborada por Frank Denis que ofrece una integración limpia con las API específicas de la plataforma.
Hannah: ¿De qué forma impide Zig que las aplicaciones se bloqueen, incluso cuando disponen de escasa memoria?
Loris: Zig explicita todas las asignaciones de memoria dinámica: no hay un asignador global o implícito como en el malloc en C: todas las funciones que quieran asignar memoria dinámica deben aceptar un asignador en la entrada. ¡Las ventajas de esta sencilla práctica son asombrosas! Si quieres centrarte en una plataforma que carezca del concepto de montón o cuyas asignaciones tengan una semántica particular (como WebAssembly), solo tienes que transmitir un asignador adecuado y se ajustará todo el código, incluso las bibliotecas. Esto también quiere decir que las bibliotecas de Zig pueden cooperar sin retrasos cuando necesites esquemas de asignaciones concretos como, por ejemplo, arenas.
Cuando se agota la memoria, todas las bibliotecas notifican el error de una forma recuperable en vez de entrar en pánico. Con la estrategia adecuada, la aplicación puede recuperarse y seguir funcionando correctamente. Aunque no siempre es fácil lograrlo, este paradigma explícito permite elaborar una ruta libre de asignaciones en un servidor web que conteste con un código de error 503 en lugar de bloquearse.
Hannah: ¿Tiene Zig algún atractivo si no eres programador de sistemas?
Loris: Es posible que sí. Supongo que depende de cuánto control quieras tener sobre tu código. Personalmente, me llamaba la atención profundizar en el mundo de la programación, pero por mi trayectoria vital nunca me había convencido toda esa imprevista complejidad de los sistemas de compilación, las preocupantes deficiencias de C y C++ y sus peculiaridades heredadas. Para mí Zig fue el modo más sencillo de lograr un mayor equilibrio como ingeniero de software. Quizás lo sea también para otras personas.
Hannah: ¿Es difícil aprender a utilizar Zig? ¿Qué recursos recomendarías a quienes quieran iniciarse en Zig?
Loris: Zig es un lenguaje sencillo. Si ya dominas lo básico de la programación de sistemas (como qué son los punteros y qué diferencia hay entre stack y montón), en un fin de semana ya podrás empezar a usarlo. Como somos un proyecto joven, todavía no hay muchos materiales didácticos, por lo que recomiendo consultar el flujo «Getting Started» que hayen el sitio web oficial y luego pasar a Zig Learn, que facilita todo cuanto se necesita saber. Más adelante, recomendaría entrar a formar parte de cualquiera de las comunidades de Zig, de modo que otros programadores de Zig puedan ayudarte en cualquier aprieto. Ah, y si lo que buscas son charlas sobre Zig, ¡échale un vistazo a Zig SHOWTIME!