Zig, Rust e Outras Linguagens

Modelo de alocação do Zig e “sem alocações ocultas”

  • Vários comentários contestam a afirmação forte do artigo de que Zig evita alocações ocultas.
  • Funções padrão de C, em sua maioria, não alocam; strdup é uma exceção notável.
  • Em Zig, a maioria das APIs da stdlib segue a convenção “passe um alocador se isto puder alocar”, mas nem todas:
    • std.Thread.spawn aloca (stack + heap para o payload dos argumentos) sem um alocador explícito.
    • std.ArrayList armazena um alocador internamente, então chamadas de método podem alocar mesmo quando nenhum alocador é passado.
    • ArrayListUnmanaged existe para manter os alocadores em um nível mais alto e tornar as alocações explícitas.
  • Alguns argumentam que isso é “apenas uma convenção” e não uma garantia estrita; outros dizem que ainda assim isso é valioso.

Trade-offs de gerenciamento de memória entre linguagens

  • Nim é destacado como uma linguagem de sistemas com gerenciamento de memória configurável; o ARC padrão é visto como mais ergonômico do que passar alocadores por todo o código Zig.
  • Contra-argumento: é possível usar um alocador global ou associar alocadores a objetos em Zig para evitar excesso de passagem de parâmetros.
  • Odin, C com boas APIs e arenas, e outras abordagens são citadas para argumentar que o design da API importa mais do que a linguagem em si.

Tamanho da biblioteca padrão vs fragmentação do ecossistema

  • Um lado prefere stdlibs compactas para evitar inchaço no estilo C++, permitir evolução mais rápida e reduzir a manutenção de longo prazo de APIs obsoletas.
  • Outro lado argumenta que stdlibs pequenas forçam a dependência de muitos pacotes de terceiros, levando à fragmentação, múltiplas bibliotecas concorrentes e inferno de dependências.
  • Exemplos:
    • Python: a grande stdlib é vista geralmente como positiva, embora alguns módulos estejam ultrapassados; bibliotecas populares de terceiros (por exemplo, clientes HTTP) ainda vencem em ergonomia.
    • Go: a stdlib é elogiada, mas partes específicas (logging, flags, o antigo net.IP) são criticadas; abstrações mais novas como netip melhoram a situação.
    • Rust: a ausência de compressão na stdlib é defendida como forma de manter domínios em evolução nos crates; outros apontam bons compressores em stdlibs de outros ecossistemas como contraexemplo.
  • Compromisso sugerido: uma stdlib central pequena + pacotes “abençoados” mantidos oficialmente, ou a adoção posterior de padrões de fato.

Gerenciadores de pacotes e preocupações com dependências

  • A história de pacotes do Zig:
    • Tem gerenciamento de pacotes via build.zig.zon e referências git; melhorias futuras na 0.12 são esperadas.
    • Não há um repositório central de pacotes por design (semelhante ao Go); alguns veem isso como mais seguro, outros como uma má decisão.
  • Preocupações gerais:
    • Vários gerenciadores concorrentes de pacotes C/C++ (vcpkg, conan, etc.) não interagem bem entre si.
    • O cargo do Rust:
      • Evita duplicação de fontes por projeto; eliminação de código morto mitiga o inchaço do binário.
      • Problemas citados: caches grandes e artefatos incrementais antigos; a futura coleta automática de lixo de cache no nightly é bem-vinda.
    • Alguns sugerem usar Nix em vez de gerenciadores específicos de linguagem.

Strings, Unicode e garantias do sistema de tipos

  • Zig:
    • Usa []const u8 para strings; por convenção, estas são UTF-8.
    • Funções muitas vezes assumem UTF-8 válido sem verificações em tempo de execução; a responsabilidade fica com o produtor.
    • Críticos comparam isso a “é só não escrever bugs” e defendem codificar invariantes de encoding nos tipos.
  • Rust:
    • Distingue String (UTF-8 proprietário) e &str (UTF-8 emprestado), com validação de UTF-8 em tempo de execução em código seguro.
    • Construtores unsafe permitem ignorar verificações apenas quando o programador promete validade.
    • Tipos separados como OsString evitam forçar UTF-8 onde isso não é garantido.
    • Esse modelo é elogiado por segurança e flexibilidade, mas criticado por complexidade e custo de aprendizado.
  • Go e outras:
    • string em Go é “apenas bytes”; pode conter dados arbitrários, sem garantia de UTF-8.
  • Suporte a Unicode:
    • std.unicode do Zig cobre validação e iteração por codepoints; suporte mais avançado (graphemes, categorias) fica em bibliotecas externas.
    • Lacunas semelhantes existem em Rust e Go; tratamento completo de Unicode (por exemplo, iteração por grapheme, ordenação sensível à localidade) é complexo e muitas vezes é delegado a bibliotecas.
  • Alguns argumentam que, como os requisitos de “string” são tão variados (mutabilidade, slicing, semântica de Unicode, desempenho), é natural que os ecossistemas cresçam com múltiplas abstrações de string, apesar de haver um tipo embutido.