Go: los enums apestan

El tratamiento que Go hace de los enums —en realidad solo constantes enteras con el ayudante `iota`— es criticado como primitivo e inseguro en comparación con sistemas de enums o tipos suma más ricos en lenguajes como Rust, Ada, Java o incluso Pascal de los años 70. Los comentaristas debaten si Go debería añadir enums verdaderos, seguros por tipos y con comprobación de exhaustividad y serialización más segura, o si su filosofía minimalista, de “usa ints y codegen/protobuf si hace falta”, es un compromiso intencional y aceptable para mantener la simplicidad y la facilidad de uso en el trabajo web y de backend típico. El intercambio también toca cuestiones más amplias de seguridad de tipos, manejo de errores y hasta qué punto un lenguaje debe añadir características frente a mantener el núcleo pequeño y opinativo.

Qué son siquiera los “enums” (enums vs tipos suma)

  • Varios comentarios distinguen entre los enums clásicos (conjuntos finitos de constantes con nombre, normalmente con respaldo entero e iteración/orden natural) y los tipos algebraicos/de suma (variantes que pueden contener datos estructurados y requieren pattern matching).
  • El enum de Rust se cita repetidamente como un tipo suma, no como un “enum verdadero” en el sentido tradicional, aunque otros sostienen que esta distinción no es muy útil en la práctica.
  • Algunos ven los intentos de colapsar enums y tipos suma en un solo concepto como confusos y dañinos conceptualmente; otros se centran en su caso de uso compartido de “elección entre alternativas”.

La historia actual de Go con los “enums”

  • Go no tiene una palabra clave dedicada para enums; el patrón habitual es type T int más const (...) con iota.
  • Críticas:
    • No es un conjunto cerrado; se puede construir cualquier int subyacente, incluidos valores inválidos.
    • No hay representación de cadena integrada, comprobación de exhaustividad en switch ni prevención de mezclar tipos de “enum” no relacionados más allá del tipo base.
    • Algunos ven iota como peligroso para valores serializados, porque reordenar constantes cambia silenciosamente las codificaciones numéricas.
  • دفاعesas:
    • Muchos consideran que iota es conciso y muy conveniente, especialmente para banderas de bits.
    • Algunos argumentan que los “enums” de Go son enums reales (constantes con nombre de un tipo distinto) y que añadir más barandillas no compensa la complejidad adicional.
    • Para algunos, pasar ints arbitrarios es obviamente un error del llamador y no un fallo del sistema de tipos.

Soluciones alternativas y herramientas

  • Patrones comunes: generadores de código (go generate, herramientas de terceros, DSLs personalizadas) para añadir conversión a cadena, integración con JSON/Protobuf y validación.
  • Se señala que los enums de Protobuf son una opción robusta si ya se usa gRPC/Protobuf, incluida una evolución segura y soporte multiplataforma.

Debate más amplio sobre diseño de lenguajes

  • Un bando elogia el minimalismo de Go, las compilaciones rápidas, el tooling simple y su idoneidad “de clase trabajadora” para tareas de REST/DevOps.
  • El otro bando califica el lenguaje de primitivo y “torpe” por resistirse a características establecidas (generics, enums adecuados, tipos suma, seguridad frente a null, restricciones de tipos más ricas).
  • Las comparaciones destacan que muchos lenguajes antiguos o de otros ecosistemas (Pascal, Ada, Rust, lenguajes ML, C#, Java) tienen enums o ADTs más potentes, con exhaustividad en tiempo de compilación y mejor integración con los sistemas de tipos.

Manejo de errores y opcionalidad

  • Algunos sostienen que los retornos explícitos de error en Go son razonables y tratan los errores como flujo de control normal.
  • Otros prefieren tipos suma al estilo Result/Either/Option y ven la falta de tales construcciones en Go (más la nulabilidad por todas partes) como una gran carencia de diseño.