Struct-of-arrays en Zig: comptime y reflexión de tipos

Fuentes: Struct-of-arrays in Zig: comptime and type reflection
Imagen generada por IA con el prompt: side by side comparison of contiguous memory blocks representing array of structs vs struct of arrays layout, minimalist technical diagram, dark background, geometric color blocks
Imagen generada con IA

En Zig, los tipos son valores en tiempo de compilación: pueden asignarse a constantes, pasarse como argumentos a funciones y devolverse desde ellas. Esta característica, conocida como comptime, es la base de los tipos genéricos del lenguaje y la pieza clave detrás de MultiArrayList, una colección de la biblioteca estándar que almacena los datos de una lista de structs mediante el esquema struct-of-arrays (SoA) en lugar del tradicional array-of-structs (AoS).

El patrón SoA es un pilar del diseño orientado a datos y de la programación orientada a arrays, técnicas empleadas en aplicaciones de alto rendimiento como motores de videojuegos, cálculo científico y compiladores. El autor lo ilustra con un struct Token de 24 bytes (un slice de 16 bytes y una enumeración kind de 8): un array de 100 instancias ocupa 2400 bytes en AoS, pero solo 1700 bytes en SoA, de los cuales 1600 corresponden a los slices de datos y 100 a las enumeraciones.

El artículo recorre la construcción de un tipo genérico en Zig con un parámetro comptime T: type, primero con un ejemplo sencillo (FixedArrayList) y después con PointN, un constructor que genera dinámicamente un struct con N campos x1, x2, x3... mediante la función @Type y metadatos StructField. La pieza restante es @typeInfo, la API de reflexión en tiempo de compilación que permite inspeccionar los campos y tipos de un struct existente para reconstruirlo como SoA.

En MultiArrayList, todos los datos se guardan en un único array de bytes que concatena los sub-arrays de cada campo. Para optimizar la alineación, los sub-arrays se ordenan en orden descendente según la alineación de su tipo, lo que obliga a almacenar una permutación de índices. El resto del código gestiona inserciones, eliminaciones, redimensionado y conversión a slice de structs mediante aritmética de punteros.

Como limitación, Zig no permite generar métodos de forma dinámica a través de la API de reflexión actual, solo campos. Se trata de una restricción documentada de la API y no del mecanismo de generación de tipos en sí.