Go Enums Suck

O tratamento de enums no Go — na prática, apenas constantes inteiras com o auxiliar `iota` — é criticado como primitivo e inseguro em comparação com sistemas de enum ou tipos soma mais ricos em linguagens como Rust, Ada, Java ou até Pascal dos anos 1970. Os comentaristas debatem se o Go deveria adicionar enums verdadeiros, tipados com segurança, verificação de exaustividade e serialização mais segura, ou se sua filosofia minimalista, de “use ints e codegen/protobuf se precisar”, é um compromisso intencional e aceitável em favor da simplicidade e facilidade de uso no trabalho típico de web e backend. A discussão também aborda questões mais amplas de segurança de tipos, tratamento de erros e até onde uma linguagem deve ir ao adicionar recursos versus manter o núcleo pequeno e opinativo.

O que “enums” realmente são (enums vs tipos soma)

  • Vários comentários distinguem enums clássicos (conjuntos finitos de constantes nomeadas, normalmente com base em inteiros e iteração/ordenação naturais) de tipos algébricos/tipos soma (variantes que podem conter dados estruturados e exigem correspondência de padrões).
  • O enum do Rust é frequentemente citado como um tipo soma, não um “enum verdadeiro” no sentido tradicional, embora outros argumentem que essa distinção não é muito útil na prática.
  • Alguns veem tentativas de fundir enums e tipos soma em um único conceito como confusas e conceitualmente prejudiciais; outros se concentram no uso comum compartilhado de “escolha entre alternativas”.

A história atual de “enum” do Go

  • O Go não tem uma palavra-chave dedicada para enum; o idiomático é type T int + const (...) com iota.
  • Críticas:
    • Não é um conjunto fechado; qualquer int subjacente pode ser construído, inclusive valores inválidos.
    • Sem representação de string embutida, verificação de exaustividade em switch, ou prevenção de mistura de tipos de “enum” não relacionados além do tipo base.
    • iota é visto por alguns como perigoso para valores serializados, já que reordenar constantes altera silenciosamente as codificações numéricas.
  • Defesas:
    • Muitos acham iota conciso e muito conveniente, especialmente para flags de bits.
    • Alguns argumentam que os “enums” do Go são enums reais (constantes nomeadas de um tipo distinto) e que proteções extras não compensam a complexidade adicional.
    • Passar ints arbitrários é visto por alguns como claramente um bug do chamador, e não uma falha do sistema de tipos.

Contornos e ferramentas

  • Padrões comuns: geradores de código (go generate, ferramentas de terceiros, DSLs personalizadas) para adicionar conversão para string, integração com JSON/Protobuf e validação.
  • Enums do Protobuf são apontados como uma opção robusta se gRPC/Protobuf já estiver em uso, incluindo evolução segura e suporte entre linguagens.

Debate mais amplo sobre design de linguagem

  • Um lado elogia o minimalismo do Go, builds rápidas, ferramentas simples e adequação “pé no chão” para trabalho de REST/DevOps.
  • O outro lado chama a linguagem de primitiva e “sem noção” em sua resistência a recursos consagrados (generics, enums adequados, tipos soma, segurança contra nulos, restrições de tipo mais ricas).
  • Comparações destacam que muitas linguagens antigas ou outras linguagens (Pascal, Ada, Rust, MLs, C#, Java) têm enums ou ADTs mais fortes, com exaustividade em tempo de compilação e melhor integração com sistemas de tipos.

Tratamento de erros e opcionalidade

  • Alguns argumentam que retornos explícitos de error no Go são sensatos e tratam erros como fluxo de controle normal.
  • Outros preferem tipos soma no estilo Result/Either/Option e veem a ausência desses construtos no Go (além da nulabilidade em todo lugar) como uma grande lacuna de design.