Zig, Rust y otros lenguajes

El modelo de asignación de Zig y “sin asignaciones ocultas”

  • Varios comentarios cuestionan la afirmación contundente del artículo de que Zig evita las asignaciones ocultas.
  • Las funciones estándar de C, en su mayoría, no asignan memoria; strdup es una excepción notable.
  • En Zig, la mayoría de las APIs de la stdlib siguen la convención de “pasa un asignador si esto podría asignar memoria”, pero no todas:
    • std.Thread.spawn asigna memoria (pila + heap para la carga útil de argumentos) sin un asignador explícito.
    • std.ArrayList almacena un asignador internamente, así que las llamadas a métodos pueden asignar memoria incluso cuando no se pasa ningún asignador.
    • ArrayListUnmanaged existe para mantener los asignadores en un nivel más alto y hacer explícitas las asignaciones.
  • Algunos sostienen que esto es “solo una convención” más que una garantía estricta; otros dicen que aun así es valioso.

Compensaciones de la gestión de memoria entre lenguajes

  • Nim se destaca como un lenguaje de sistemas con gestión de memoria configurable; se ve el ARC predeterminado como más ergonómico que pasar asignadores a través del código Zig.
  • Contrapunto: se puede usar un asignador global o asociar asignadores a objetos en Zig para evitar un exceso de cableado.
  • Odin, C con buenas APIs y arenas, y otros se citan para argumentar que el diseño de la API importa más que el lenguaje en sí.

Tamaño de la biblioteca estándar vs fragmentación del ecosistema

  • Un bando prefiere stdlibs compactas para evitar la hinchazón al estilo C++, permitir una evolución más rápida y reducir el mantenimiento a largo plazo de APIs obsoletas.
  • Otro bando argumenta que las stdlibs pequeñas obligan a depender de muchos paquetes de terceros, lo que conduce a fragmentación, múltiples bibliotecas en competencia y un infierno de dependencias.
  • Ejemplos:
    • Python: la gran stdlib se considera en general positiva, aunque algunos módulos están desfasados; las bibliotecas populares de terceros (p. ej., clientes HTTP) siguen ganando en ergonomía.
    • Go: se elogia la stdlib, pero se critican partes concretas (logging, flags, el anterior net.IP); abstracciones más nuevas como netip mejoran las cosas.
    • Rust: la ausencia de compresión en la stdlib se defiende como una forma de mantener en crates los dominios en evolución; otros señalan compresores buenos en las stdlibs de otros ecosistemas como contraejemplo.
  • Compromiso sugerido: una stdlib central pequeña + paquetes “bendecidos” mantenidos oficialmente, o la adopción posterior de estándares de facto.

Gestores de paquetes y preocupaciones sobre dependencias

  • La historia de paquetes de Zig:
    • Tiene gestión de paquetes mediante build.zig.zon y referencias git; se esperan mejoras próximas en la 0.12.
    • No hay un repositorio central de paquetes por diseño (similar a Go); algunos lo ven como más seguro, otros como una mala decisión.
  • Preocupaciones generales:
    • Múltiples gestores de paquetes competidores para C/C++ (vcpkg, conan, etc.) no interoperan bien.
    • cargo de Rust:
      • Evita la duplicación de fuentes por proyecto; la eliminación de código muerto mitiga la hinchazón de binarios.
      • Problemas citados: grandes cachés y artefactos incrementales obsoletos; se da la bienvenida a la futura recolección automática de basura de caché en nightly.
    • Algunos sugieren usar Nix en lugar de gestores específicos del lenguaje.

Cadenas, Unicode y garantías del sistema de tipos

  • Zig:
    • Usa []const u8 para cadenas; por convención, estas son UTF-8.
    • Las funciones a menudo asumen UTF-8 válido sin comprobaciones en tiempo de ejecución; la responsabilidad recae en el productor.
    • Los críticos lo comparan con “simplemente no escribas bugs” y argumentan a favor de codificar invariantes de codificación en los tipos.
  • Rust:
    • Distingue String (UTF-8 poseído) y &str (UTF-8 prestado), con validación UTF-8 en tiempo de ejecución en código seguro.
    • Los constructores inseguros permiten omitir comprobaciones solo cuando el programador promete la validez.
    • Tipos separados como OsString evitan forzar UTF-8 donde no está garantizado.
    • Este modelo se elogia por su seguridad y flexibilidad, pero se critica por su complejidad y la carga de aprendizaje.
  • Go y otros:
    • string de Go es “solo bytes”; puede contener datos arbitrarios, no está garantizado que sea UTF-8.
  • Soporte Unicode:
    • std.unicode de Zig cubre la validación y la iteración por codepoints; un soporte más avanzado (graphemes, categorías) está en bibliotecas externas.
    • Existen lagunas similares en Rust y Go; el manejo completo de Unicode (p. ej., iteración por graphemes, ordenación sensible a la configuración regional) es complejo y a menudo se delega a bibliotecas.
  • Algunos argumentan que, dado que los requisitos de “string” son tan variados (mutabilidad, slicing, semántica Unicode, rendimiento), es natural que los ecosistemas desarrollen múltiples abstracciones de cadena pese a tener un tipo incorporado.