⚡ Zig — 2016

⬅️ Atlas · 🗂️ Todas las fichas · 📚 Índice de clases

Zig es la propuesta más radical de las que intentan suceder a C: no añadir seguridad automática, sino hacer visible todo lo que C esconde. Cada reserva de memoria, cada operación que puede fallar y cada rama del flujo de control aparecen escritas — y a cambio no hay nada oculto.

🎯 Por qué está en este programa

Zig es un primo de la familia C / llaves (Atlas) y aparece junto a los representantes de sistemas del núcleo, Go y Rust.

Aporta al programa dos ideas que ningún otro lenguaje del curso enseña igual: el asignador de memoria como parámetro explícito —quien llama decide de dónde sale la memoria (clases 128 y 130)— y comptime, ejecutar código del propio lenguaje en tiempo de compilación en lugar de tener un lenguaje de macros aparte (clase 122).

Año 2016; en 0.x — aún no ha llegado a 1.0
Autoría Andrew Kelley; hoy con la Zig Software Foundation
Familia Sistemas / C; sin herencia sintáctica de C++
Paradigma Imperativo y procedimental; sin clases ni herencia
Tipado Estático y fuerte, con genéricos vía comptime y tipos opcionales
Memoria Manual y explícita, con asignadores que se pasan como argumento
Ejecución Compilado a nativo (LLVM y motor propio); compilador cruzado universal
Estado 🟡 Preestándar: se usa en producción con cuidado, y la API cambia

📜 Historia

Andrew Kelley empezó Zig en 2015 por frustración con C y con C++: quería un lenguaje donde no hubiera control de flujo oculto —nada de constructores, destructores, sobrecarga de operadores ni excepciones— y donde cada reserva de memoria fuera visible.

El proyecto creció con una propiedad inesperada que lo hizo conocido antes que el lenguaje: zig cc es un compilador de C excelente, con compilación cruzada a cualquier plataforma sin instalar nada más.

zig cc -target aarch64-linux-musl hola.c    # desde cualquier máquina, sin cadena cruzada

Eso resolvió, de rebote, uno de los problemas más molestos de la clase 174, y hizo que mucha gente usara Zig como herramienta antes que como lenguaje. Bun, el tiempo de ejecución de JavaScript, está escrito en Zig.

El lenguaje sigue antes de la 1.0, con cambios incompatibles en cada versión —el sistema de entrada y salida se está rediseñando ahora mismo— y con el compilador migrando de LLVM a un motor propio.

🏭 Dónde vive hoy

🧠 Lo que enseña: hacer visible lo que C esconde

Uno, el asignador explícito. En Zig, una función que reserva memoria recibe de dónde sacarla:

fn crearLista(asignador: std.mem.Allocator, n: usize) ![]u32 {
    return try asignador.alloc(u32, n);
}

Y eso cambia el diseño entero de la biblioteca estándar: no hay un montón global implícito. Quien llama decide si la memoria viene del montón, de una arena que se libera de golpe, de un búfer en la pila o de un asignador que detecta fugas en las pruebas (clases 130 y 139).

Es la idea que la clase 128 persigue —saber de dónde sale la memoria— convertida en firma de función.

Dos, los errores son valores y el flujo está escrito:

const valor = try puedeFallar();    // ← 'try' propaga el error; SIEMPRE se ve

No hay excepciones, como en Go, pero el error forma parte del tipo (!u32), así que ignorarlo no compila (clase 116).

Y tres, comptime:

fn Lista(comptime T: type) type {          // los genéricos son FUNCIONES sobre tipos
    return struct { items: []T };
}

El mismo lenguaje se ejecuta en tiempo de compilación para generar tipos, desplegar bucles o calcular tablas. Es la metaprogramación de la clase 123 sin un lenguaje de macros aparte — lo contrario del preprocesador de C y de las plantillas de C++.

Y la comparación con Rust es la que importa (clase 164): Rust hace imposible el error de memoria; Zig lo hace visible. Zig detecta el desbordamiento y el uso de memoria no inicializada en modo depuración, y en modo seguro comprueba límites — pero no tiene comprobador de préstamos, así que un uso después de liberar sigue siendo posible. Son dos apuestas distintas sobre el mismo problema, y merece conocer las dos antes de opinar.

🔄 Hacia dónde va

⚙️ Cómo se ejecuta hoy

zig run main.zig < entrada.txt
zig build-exe main.zig -O ReleaseSafe        # con comprobaciones; o ReleaseFast
zig build test                                # pruebas, integradas en el lenguaje

zig cc -target x86_64-windows-gnu hola.c      # ← compilar C para otra plataforma

🧪 El programa de la clase 041 en Zig

const std = @import("std");

pub fn main() !void {
    var buf: [128]u8 = undefined;
    const linea = (try std.io.getStdIn().reader().readUntilDelimiterOrEof(&buf, '\n')).?;
    var it = std.mem.tokenizeScalar(u8, std.mem.trim(u8, linea, " \r"), ' ');
    const precio = try std.fmt.parseFloat(f64, it.next().?);
    const cantidad = try std.fmt.parseFloat(f64, it.next().?);
    const descuento = try std.fmt.parseFloat(f64, it.next().?);
    const total = precio * cantidad * (1 - descuento);
    try std.io.getStdOut().writer().print("Total: {d:.2}\n", .{total});
}

Lo que hay que ver, y es la ficha donde más se nota.

📚 Fuentes y bibliografía


⏮️ Volver al Atlas · 🗂️ Todas las fichas · 🔗 Relacionadas: C · Rust · Go · Nim · D