Zig (lenguaje de programación) - Enciclopedia
Zig es un lenguaje de programación sistemático imperativo, de propósito general, estáticamente tipado y compilado, diseñado por Andrew Kelley. Es un software libre y de código abierto, lanzado bajo una Licencia MIT.
Uno de los objetivos principales del lenguaje es mejorar el lenguaje C, con la intención de ser aún más pequeño y más simple de programar, mientras ofrece más funcionalidad. Las mejoras en la simplicidad del lenguaje se relacionan con el control de flujo, las llamadas a funciones, las importaciones de bibliotecas, la declaración de variables y el soporte Unicode. Además, el lenguaje no utiliza macros ni instrucciones del preprocesador. Las características adoptadas de los lenguajes modernos incluyen la adición de tipos de programación genéricos en tiempo de compilación, que permiten que las funciones funcionen con una variedad de datos, junto con un pequeño conjunto de nuevas directivas del compilador para permitir el acceso a la información sobre esos tipos utilizando programación reflexiva (reflexión). Al igual que C, Zig omite la recolección de basura y tiene gestión de memoria manual. Para ayudar a eliminar los errores potenciales que surgen en estos sistemas, incluye tipos de opción, una sintaxis sencilla para su uso y un marco de pruebas unitarias integrado en el lenguaje. Zig tiene muchas características para la programación de bajo nivel, destacando estructuras empacadas (estructuras sin relleno entre campos), enteros de ancho arbitrario y múltiples tipos de punteros.
La principal desventaja del sistema es que, aunque Zig tiene una comunidad en crecimiento, hasta 2025 sigue siendo un lenguaje nuevo con áreas para mejorar en madurez, ecosistema y herramientas. Además, la curva de aprendizaje de Zig puede ser pronunciada, especialmente para aquellos que no están familiarizados con los conceptos de programación de bajo nivel. La disponibilidad de recursos de aprendizaje es limitada para casos de uso complejos, aunque esto está mejorando gradualmente a medida que aumenta el interés y la adopción. Otros desafíos mencionados por los revisores incluyen la interoperabilidad con otros lenguajes (se requiere un esfuerzo adicional para gestionar el marshaling de datos y la comunicación), así como la dealocación de memoria manual (ignorar la gestión adecuada de la memoria lleva directamente a fugas de memoria).
El desarrollo es financiado por la Fundación de Software Zig (ZSF), una corporación sin fines de lucro con Andrew Kelley como presidente, que acepta donaciones y contrata múltiples empleados a tiempo completo. Zig tiene una comunidad de contribuyentes muy activa y aún se encuentra en sus etapas iniciales de desarrollo. A pesar de esto, una encuesta de Stack Overflow en 2024 encontró que los desarrolladores de software Zig ganan un promedio de $103,000 USD al año, lo que lo convierte en uno de los lenguajes de programación mejor pagados. Sin embargo, solo el 0.83% informó que eran hábiles en Zig.
Lenguaje
= Objetivos =
El objetivo principal de Zig es ser una mejor solución para las tareas que actualmente se resuelven con C. Una preocupación principal en ese aspecto es la legibilidad; Zig intenta usar conceptos y sintaxis existentes siempre que sea posible, evitando la adición de sintaxis diferente para conceptos similares. Además, está diseñado para "robustez, optimidad y mantenibilidad", incluyendo una variedad de características para mejorar la seguridad, la optimización y las pruebas. La sintaxis pequeña y simple es una parte importante de la mantenimiento, ya que es un objetivo del lenguaje permitir a los mantenedores depurar el código sin tener que aprender las complejidades de un lenguaje con el que no estén familiarizados. Incluso con estos cambios, Zig puede compilar contra y en código C existente; se pueden incluir encabezados de C en un proyecto de Zig y llamar a sus funciones, y el código de Zig se puede enlazar a proyectos de C incluyendo los encabezados construidos por el compilador.
En línea con la filosofía general de diseño de hacer el código simple y fácil de leer, el sistema Zig en su conjunto también abarca varios cambios estilísticos en comparación con C y otros lenguajes de estilo C. Por ejemplo, el lenguaje Rust tiene sobrecarga de operadores, lo que significa que una declaración como a = b + c podría ser una llamada a una versión sobrecargada del operador más del tipo. Además, esa función podría fallar, lo que podría prever cualquier código siguiente. En Zig, si algo llama a una función, se parece a una llamada a una función; si no, no se parece a una llamada a una función. Si puede lanzar un error, se hace explícito en la sintaxis, y la gestión de errores se realiza mediante tipos de error y puede manejarse con catch o try.
Los objetivos de Zig contrastan con los de muchos otros lenguajes diseñados en el mismo período, como Rust, Carbon y Nim. Generalmente, estos lenguajes son más complejos con características adicionales como sobrecarga de operadores, funciones que se disfrazan como valores (propiedades) y muchas otras características destinadas a ayudar a construir programas grandes. Este tipo de características tiene más en común con el enfoque de C++, y estos lenguajes están más alineados con ese lenguaje. Zig tiene una extensión más conservadora del sistema de tipos, que admite genéricos en tiempo de compilación y admite una forma de tipado de pato con la directiva comptime.
= Manejo de memoria =
Una de las principales fuentes de errores en los programas C es el sistema de gestión de memoria, basado en malloc. malloc reserva un bloque de memoria para uso en el código y devuelve una referencia a esa memoria como puntero. No hay sistema para garantizar que la memoria se libere cuando el programa ya no la necesita, lo que puede llevar a que los programas usen todo el espacio disponible en memoria, lo que resulta en fugas de memoria. Más común es el puntero suelto que no se refiere a un objeto de memoria adecuadamente asignado.
Una solución común a estos problemas es el recolector de basura (GC), que examina el programa en busca de punteros a memoria previamente asignada y elimina cualquier bloque que ya no tenga nada apuntando a él. Aunque esto reduce o incluso elimina considerablemente los errores de memoria, los sistemas de GC son relativamente lentos en comparación con la gestión de memoria manual, y tienen un rendimiento impredecible que los hace inadecuados para la programación de sistemas. Otra solución es la conteo automático de referencias (ARC), que implementa el mismo concepto básico de identificar bloques de memoria no utilizada, pero lo hace en el momento de la creación y destrucción del puntero, manteniendo el número de punteros a un bloque, lo que significa que no es necesario realizar búsquedas exhaustivas de punteros, que se vuelven innecesarias a cambio de agregar el sobrecosto de ajuste del contador de referencias a cada operación de creación y destrucción de puntero.
Zig tiene como objetivo proporcionar un rendimiento similar o mejor al de C, por lo que GC y ARC no son soluciones adecuadas. En su lugar, utiliza un concepto moderno conocido como tipos de opción, desde 2022. En lugar de permitir que un puntero apunte a nada, o nil, se utiliza un tipo separado para indicar datos que opcionalmente están vacíos. Esto es similar a usar una estructura con un puntero y un booleano que indica si el puntero es válido, pero el estado del booleano se gestiona de manera invisible por el lenguaje y no necesita ser gestionado explícitamente por el programador. Por ejemplo, cuando se declara un puntero, se establece en "no asignado", y cuando ese puntero recibe un valor de malloc, se establece en "asignado" si el malloc tiene éxito.
La ventaja de este modelo es que tiene un costo muy bajo o nulo; el compilador debe crear el código para pasar el tipo de opción cuando se manipulan los punteros, en lugar de un puntero simple, pero esto le permite expresar directamente los problemas posibles de memoria en tiempo de compilación sin necesidad de soporte en tiempo de ejecución. Por ejemplo, crear un puntero con un valor nulo y luego intentar usarlo es perfectamente aceptable en C, lo que lleva a errores de puntero nulo. Por el contrario, un lenguaje que utiliza tipos de opción puede verificar que todos los caminos de código solo intenten usar punteros cuando son válidos. Aunque esto no elimina todos los posibles problemas, cuando ocurren problemas en tiempo de ejecución, el error se puede ubicar y explicar con mayor precisión.
Otra cambio para la gestión de memoria en Zig es que la asignación real se maneja a través de estructuras que describen la acción, en lugar de llamar a las funciones de gestión de memoria en libc. Por ejemplo, en C, si se desea escribir una función que cree una cadena que contenga múltiples copias de otra cadena, la función podría tener este aspecto:
En el código, la función examinaría el tamaño original y luego malloc multiplicado por esa longitud para reservar memoria para la cadena que construirá. Ese malloc es invisible a las funciones que lo llaman, y si fallan al liberar la memoria más tarde, ocurrirá una fuga de memoria. En Zig, esto podría manejarse utilizando una función como esta:
En este código, la variable asignadora se pasa una estructura que describe qué código debe realizar la asignación, y la función repeat devuelve o bien la cadena resultante o, usando el tipo de opción como indica el !, un Allocator.Error. Al expresar directamente al asignador como entrada, la asignación de memoria nunca se "oculta" dentro de otra función, siempre se expone a través de la API por la función que ultimately solicita que se asigne la memoria. No se realizan asignaciones dentro de la biblioteca estándar de Zig. Además, ya que la estructura puede apuntar a cualquier cosa, se pueden usar asignadores alternativos, incluso aquellos escritos en el programa. Esto permite, por ejemplo, asignadores de objetos pequeños que no utilizan las funciones del sistema operativo que normalmente asignan una página completa de memoria.
Los tipos de opción son un ejemplo de una característica de lenguaje que ofrece funcionalidad general mientras sigue siendo simple y genérica. No es necesario usarlos para resolver problemas de puntero nulo; también son útiles para cualquier tipo de valor donde "sin valor" es una respuesta adecuada. Considere una función countTheNumberOfUsers que devuelve un entero, y una variable entera, theCountedUsers, que holds el resultado. En muchos lenguajes, se colocaría un número mágico en theCountedUsers para indicar que countTheNumberOfUsers no se ha llamado aún, mientras muchas implementaciones simplemente lo establecen en cero. En Zig, esto podría implementarse como un var theCountedUsers: ?i32 = null que establece la variable en un valor claro de "no llamado".
Otra característica más general de Zig que también ayuda a gestionar problemas de memoria es el concepto de defer, que marca某些 código para que se ejecute al final de una función sin importar lo que ocurra, incluso errores de tiempo de ejecución. Si una función específica asigna cierta memoria y luego la libera cuando la operación está completa, se puede agregar una línea para defer una liberación para asegurarse de que se libere independientemente de lo que ocurra.
La gestión de memoria de Zig evita la asignación oculta. La asignación no se gestiona directamente en el lenguaje. En su lugar, el acceso a la pila se realiza a través de la biblioteca estándar, explícitamente.
= Interacción directa con C =
Zig promueve un enfoque gradual hacia la portabilidad que combina nuevo código de Zig con código C existente. Para hacerlo, busca hacer que la interacción con las bibliotecas C existentes sea lo más fluida posible. Zig importa sus propias bibliotecas con la directiva @import, generalmente de la siguiente manera:
El código de Zig dentro de ese archivo puede llamar a funciones dentro de std, por ejemplo:
Para trabajar con código C, simplemente se reemplaza @import con @cImport:
El código de Zig puede ahora llamar a funciones en la biblioteca soundio como si fueran código Zig nativo. Como Zig utiliza tipos de datos nuevos que se definen explícitamente, a diferencia de los int y float más genéricos de C, se utilizan una pequeña cantidad de directivas para mover datos entre los tipos de C y Zig, incluyendo @intCast y @ptrCast.
= Comptime =
Al usar la palabra clave comptime, el programador puede evaluar explícitamente secciones de código en tiempo de compilación en lugar de tiempo de ejecución. Ser capaz de ejecutar código en tiempo de compilación permite a Zig tener la funcionalidad de macros y compilación condicional sin necesidad de un lenguaje separado de preprocesador.
Durante el tiempo de compilación, los tipos se convierten en ciudadanos de primera clase. Esto permite el tipado de pato en tiempo de compilación, y es así como Zig implementa tipos genéricos.
Por ejemplo, en Zig, un tipo de lista enlazada genérica podría implementarse utilizando una función como esta:
Esta función toma un tipo T y devuelve una estructura personalizada que define una lista enlazada con ese tipo de datos.
Compilador
Zig también incluye un compilador de C y C++, y puede utilizarse con uno o ambos lenguajes mediante los comandos zig cc y zig c++, proporcionando muchos encabezados, incluyendo la biblioteca estándar C (libc) y la Biblioteca Estándar C++ (libcxx) para varias plataformas. Esto permite que los subcomandos cc y c++ de Zig actúen como compiladores cruzados por defecto (similar a Clang).
Zig trata la compilación cruzada como un caso de uso de primera clase del lenguaje. Esto significa que cualquier compilador Zig puede compilar binarios ejecutables para cualquier plataforma de destino, de las cuales hay docenas. Estas incluyen no solo sistemas modernos ampliamente utilizados como ARM y x86-64, sino también PowerPC, SPARC, MIPS, RISC-V, LoongArch64 e incluso las arquitecturas IBM z (S390). La herramienta de cadena puede compilar a cualquiera de estos objetivos sin instalar software adicional, todo el soporte necesario está en el sistema básico. Se proporciona también soporte experimental para plataformas menos conocidas como las GPUs AMD y Nvidia o las consolas PlayStation 4 y 5 (con diferentes grados de soporte).
La compilación cruzada también está disponible para una variedad de sistemas operativos (principalmente de escritorio). Los UNIX-like populares y Windows están oficialmente soportados (y documentados), pero se pueden y se han creado aplicaciones (con diferentes grados de soporte) para Android (con Android NDK) o iOS.
Zig utiliza LLVM (escrito en C++) como backend para la optimización. Desde la versión 0.10, el compilador Zig se escribe en el lenguaje de programación Zig, es decir, es un compilador autoalojado. El enlazador autoalojado está estrechamente relacionado con el compilador autoalojado.
El backend de LLVM es el predeterminado para la mayoría de los objetivos, excepto SPIR-V. Zig también admite su backend autoalojado, que se puede activar utilizando -fno-llvm.
Paquetes
La versión 0.11.0 incluye un administrador de paquetes experimental, pero no hay disponible un repositorio oficial de paquetes. En su lugar, un paquete es simplemente una URL que apunta a un archivo comprimido o a un repositorio Git. Cada paquete idealmente incluye un archivo build.zig estándar (que el compilador Zig utiliza por convención para compilar el código fuente) y un archivo build.zig.zon que contiene metadatos con el nombre y la versión del paquete.
Ejemplos
= Hola Mundo =
= Lista enlazada genérica =
Salida
= Repetición de cadenas con asignador =
Salida
Historia
El nombre “Zig” fue elegido a través de un proceso que involucraba un script de Python que combinaba aleatoriamente letras, comenzando con la letra “Z” y seguido por una vocal o “Y”, con el objetivo de generar palabras de cuatro letras. A pesar de la longitud intencionada, “Zig”, una palabra de tres letras, fue seleccionada finalmente entre las combinaciones generadas por el script.
El compilador de autoaplicación anterior, escrito en Zig y C++ utilizando LLVM como backend y que admitía muchos de sus objetivos nativos, se eliminó en la versión 0.11. Las versiones más recientes de Zig utilizan una versión precompilada de WebAssembly de Zig para autoaplicarse.
= Versiones =
Todas las versiones, junto con sus fechas de lanzamiento y plataformas precompiladas.
Proyectos
Bun es un runtime de JavaScript y TypeScript escrito en Zig, utilizando el motor JavaScriptCore de Safari.
Ghostty es un emulador de terminal escrito en Zig.
La base de datos financiera TigerBeetle está escrita en Zig.
Deecy, un emulador en desarrollo (última versión publicada en este momento es la 0.3.0) de la plataforma de consola de videojuegos Sega Dreamcast, completamente escrito en Zig desde cero.
Ver también
D
V
Referencias
= Citaciones =
= Bibliografía =
Elizabeth, Jane (2017-10-19). "Tired of C? New programming language Zig aims to be more pragmatic and readable". jaxenter. Archived from the original on 2020-10-01. Retrieved 2020-04-22.
Yegulalp, Serdar (2016-08-29). "New challenger joins Rust to topple C language". InfoWorld. Retrieved 2020-02-11.
Owens, Jeffery (2023-12-02). Mastering Zig Programming. Independently Published. ISBN 979-8870587332.
Allen, Corby (2024-06-20). Zig Programming Mastery. Independently Published. ISBN 979-8329021424.
Enlaces externos
Sitio web oficial
Zig en GitHub
Película: Introducing Zig
Película: The Road to 1.0
Zig Weekly