- A lógica de resolução de tipos (type resolution) do compilador Zig foi completamente redesenhada, simplificando a estrutura interna e trazendo melhorias visíveis também para os usuários
- O novo design passa a tratar de forma preguiçosa (lazy) a análise dos campos de tipos, evitando inspecionar desnecessariamente a estrutura detalhada de tipos não inicializados
- As mensagens de erro de loop de dependência (dependency loop) foram aprimoradas de forma mais específica, permitindo identificar com clareza a causa do loop
- O problema de análise excessiva na compilação incremental (incremental compilation) e vários bugs foram corrigidos, aumentando significativamente a velocidade de build
- Esta mudança inclui dezenas de correções de bugs e pequenos aprimoramentos na linguagem, fortalecendo de forma geral o desempenho e a experiência de desenvolvimento do compilador Zig
Redesenho da lógica de resolução de tipos
- Um PR de cerca de 30 mil linhas foi mesclado, reescrevendo a lógica de resolução de tipos do compilador Zig com uma estrutura mais lógica e intuitiva
- Nesse processo, a estrutura interna do compilador foi reorganizada, com efeitos de melhoria também perceptíveis diretamente pelos usuários
- O compilador foi alterado para fazer avaliação preguiçosa da análise de campos de tipos, deixando de explorar desnecessariamente a estrutura detalhada de tipos não inicializados
- No código de exemplo, quando uma struct que inclui um campo
@compileError é usada apenas como namespace, antes ocorria erro de compilação, mas agora a compilação acontece normalmente
- Isso evita dependências de código desnecessárias ao usar tipos em forma de namespace, como
std.Io.Writer
Melhoria nas mensagens de erro de loop de dependência
- Antes, as mensagens de erro de loop de dependência eram ambíguas, mas agora mostram com clareza a causa e a posição do loop
- No código de exemplo, quando as structs
Foo e Bar referenciam uma à outra, a mensagem de erro aponta de forma específica o local de dependência de cada tipo
- A mensagem inclui o comprimento do loop, a posição de declaração de cada campo e a posição da consulta de alinhamento
- Mesmo em loops complexos, ela fornece informação suficiente para identificar facilmente a causa do problema
Melhorias de desempenho na compilação incremental
- Com esta mudança, vários bugs da compilação incremental foram corrigidos
- Em especial, o problema de “análise excessiva (over-analysis)” foi resolvido, otimizando a recompilação para atingir apenas as partes alteradas
- Como resultado, em muitos casos a velocidade de compilação aumenta bastante
- Os desenvolvedores podem ativar a compilação incremental no Zig 0.15.1 ou superior para experimentar uma experiência de desenvolvimento melhorada
Outras melhorias
- Este PR inclui dezenas de correções de bugs, pequenas mudanças na linguagem e melhorias de desempenho do compilador
- A maioria diz respeito a casos detalhados ou específicos
- O histórico completo das mudanças pode ser visto no Codeberg em PR #31403
- Ao encontrar novos bugs, recomenda-se reportar uma issue
Significado da mudança
- Com a simplificação da lógica de resolução de tipos e a otimização da compilação incremental, a estabilidade e a eficiência do compilador Zig foram reforçadas
- Os desenvolvedores passam a receber feedback mais rápido e mais claro, e podem esperar ganhos de produtividade mesmo em codebases grandes
1 comentários
Comentários no Hacker News
Sou o autor deste devlog
Entendo a preocupação com a quebra de compatibilidade causada por mudanças na linguagem, mas quero deixar claro que esta alteração no compilador não está num nível de impacto tão grande
Por exemplo, ao compilar o ZLS com a nova branch, só foi preciso fazer mudanças como trocar
.{}por.empty. Isso aconteceu por causa da remoção do valor padrão destd.ArrayList, que já estava em estado deprecated há 1 anoE no caso do projeto Awebo, também só houve três pontos a corrigir em toda a árvore de dependências — mudança para
.empty, adição decomptimee adição deorelse @alignOf(T)A maioria dessas correções são mudanças simples que, para a maior parte dos desenvolvedores Zig, viram quase um reflexo automático
O ponto principal deste PR não é a quebra, e sim a correção de bugs e a melhora da compilação incremental
Acho que a qualidade e o planejamento do PR são muito altos, e minha intenção nunca foi menosprezar o esforço do autor
Só tirei disso a lição de que, no futuro, devo comentar mais e deixar opiniões com mais cuidado
lib/std/multi_array_list.zigNão entendo por que usar
@alignOf(T)na definição deMultiArrayList(T)causaria uma dependência circularMesmo que
Tfosse o próprioMultiArrayList, isso não seria um tipo monomórfico completamente separado? Acho que estou deixando passar alguma coisaCódigo relacionado: link
Tenho curiosidade sobre a experiência de quem usa Zig em ambiente de produção
Como a linguagem muda com frequência, queria saber como são os ciclos de atualização ou reescrita, e se acontece de pacotes dependentes ficarem para trás em relação à versão da linguagem
Sei que o Bun aproveita bem Zig, mas gostaria de ouvir outros casos também
Nos últimos 1~2 anos, as mudanças na linguagem e na biblioteca padrão avançaram sem grandes problemas
Antes os upgrades eram incômodos, mas hoje parecem algo como um “pequeno transtorno”
Se alguém me perguntar sobre a experiência de usar Zig, essa parte é tão estável que eu quase nem mencionaria
Projetos grandes assim fazem upgrade com base em releases tagueadas, e normalmente concluem a migração em alguns dias ou poucas semanas
Também quase não há dependências, então o peso do upgrade não é grande
Mas às vezes um pequeno erro de digitação causa um crash do compilador com SIGBUS, o que dificulta o debug
O
.zig-cachejá chegou a 173GB, o que também pode causar problemas em VPS ARMAo atualizar o
lightpandade 0.14 para 0.15, tudo correu bem. O 0.16 também não deve trazer grandes problemasMas, como desenvolvedor de biblioteca, é difícil acompanhar o ritmo acelerado das mudanças no 0.16
No momento estou lidando com isso só de forma experimental na branch “dev”
Reescrevi módulos de Node.js/TypeScript em Zig, e ficou 2x mais rápido com 70% menos uso de memória
O suporte de Zig para serialização
sqlite/JSONfoi uma grande vantagemO ponto fraco é a falta de sintaxe para closures ou vtables, o que dificulta separar melhor as camadas do código
Usei
Arcse alocadores bump para garantir segurança de memória, e pretendo continuar operando em modo DebugSafeMudar para ReleaseFast trouxe um ganho de 25% em velocidade, mas não o bastante para compensar a perda de segurança
Mesmo que seja preciso ajustar código, no longo prazo essa é a abordagem correta
Fiquei impressionado com o trabalho da equipe do Zig
Uso com frequência o terminal ghostty feito em Zig, e ele é muito estável
Mas, pessoalmente, prefiro Rust
Rust adota um modelo de “mundo fechado”, enquanto Zig segue um modelo de “mundo aberto”
Em Rust é preciso implementar traits explicitamente, mas em Zig basta o formato (shape) do tipo bater para funcionar
Isso permite um metaprogramação poderosa em Zig, mas também tem a desvantagem de tornar inferência de tipos, autocompletar, documentação e suporte de LSP mais difíceis
Pela explicação, isso parece parecido com interfaces de Go, mas até onde sei Zig não tem um conceito correspondente direto
A transição de
kernel32paraNtdllfoi interessanteÉ uma ideia que também pode ser aplicada à API de espaço de usuário no Linux
Em especial, a forma de tratar erros na fronteira entre kernel e usuário é parecida
Mas no Linux libc e kernel estão tão ligados que o uso de
errnoé indispensávelFico curioso sobre por que esse padrão também surgiu no Windows
errnoouGetLastError()é um legado da era anterior às threadsNo passado havia escalonamento cooperativo, então variáveis globais eram seguras, mas isso ficou perigoso com o surgimento de multicore e threads
Por isso o thread local apareceu como alternativa
Em vez de usar tipos como namespaces, será que não seria melhor adicionar namespaces explícitos à linguagem?
A abordagem é adicionar algo só quando for uma funcionalidade que traga otimização em vários pontos
Em Zig,
@importtransforma um arquivo em uma struct, e namespaces são representados simplesmente como structs aninhadasOu seja, namespace não passa de outro import
(Ainda não tomei café o bastante, então não garanto total precisão)
Há um ponto que muitas vezes passa despercebido em discussões sobre mudanças na linguagem — o impacto no ecossistema
Se a linguagem quebra com frequência, não são só os apps que precisam acompanhar, mas também bibliotecas, ferramentas e tutoriais
No fim, isso tende a puxar o ecossistema para projetos ativamente mantidos, em vez de bibliotecas feitas uma vez e depois abandonadas
Isso pode ser um trade-off razoável na fase inicial de design da linguagem, mas no longo prazo afeta o crescimento do ecossistema
Outras linguagens novas estão investindo bastante em minimizar esse cansaço de mudança
Também é interessante observar que resultado a abordagem do Zig vai produzir
O Blender quebra a API com frequência, mas a maioria das correções é pequena
Ainda assim, alguém precisa fazer essas correções, e quando a manutenção para, o usuário acaba tendo de aplicar patch por conta própria
Addons pagos têm mais chance de continuar sendo mantidos, mas nem isso é garantia
Biblioteca sem manutenção já é código ruim de qualquer forma
Em vez de criticar Zig, queria que parassem de promover outras linguagens (como C3)
A afirmação no PR do Zig de que “Chromium, boringssl, Firefox e Rust chamam SystemFunction036 de advapi32.dll” não é verdadeira
Eles já usam ProcessPrng, e desde o Windows 10 isso não falha
A base para isso está no whitepaper da Microsoft
O sistema foi projetado para que pedidos de RNG nunca falhem, e se isso acontecer o próprio processo é encerrado
Ou seja, ele não retorna código de erro justamente para garantir números aleatórios de alta qualidade
A semântica da linguagem de Zig parece simples na superfície, mas as interações são sutis
Isso me faz pensar que, com o tempo, podem surgir casos de borda complexos, como aconteceu com as regras de templates de C++
Um PR com 30 mil linhas é uma conquista impressionante
Mas fiquei surpreso porque mudar a semântica da linguagem é algo muito sério
Entendo que Zig ainda não chegou ao 1.0 e por isso as mudanças são rápidas, mas a forma casual de dizer “mudei a semântica nesta branch” me pareceu um pouco desconcertante
Fico curioso se esse tipo de mudança grande faz parte da cultura do Zig, ou se sou eu que estou ficando para trás
A expressão “modern Zig” também me fez rir, considerando a velocidade com que a linguagem muda
O devlog não é texto de marketing, e sim algo mais próximo de um registro para iniciados, e Zig ainda não é 1.0
O PR traz contexto e fundamentação suficientes
Ao escolher Zig, você já aceita um certo nível de risco de mudança na linguagem
Na verdade, limpar essas coisas agora tende a ser melhor no longo prazo
(Basta pensar em heranças impossíveis de corrigir, como a precedência dos operadores de bits em C)
mluggé contribuidor central do Zig e membro da Zig FoundationEsta mudança foi feita para eliminar dependências circulares e reorganizar o sistema de tipos
As propostas relacionadas estão públicas em #3257 e #15909
Com isso, a resolução de tipos do Zig passa a ser organizada como um DAG (grafo acíclico direcionado), melhorando muito a estabilidade do compilador
Zig opera sob um modelo BDFN (Benevolent Dictator For Now), e a palavra final é de Andrew Kelley
Mas a equipe é uma organização sem fins lucrativos e coloca a confiança dos usuários e a qualidade da linguagem acima de tudo
Pessoalmente, é uma grande honra trabalhar com Matthew
Ela era formalmente perfeita, mas na prática virou uma linguagem do caos