Go Enums Suck
Go’s treatment of enums—really just integer constants with the `iota` helper—is criticized as primitive and unsafe compared to richer enum or sum-type systems in languages like Rust, Ada, Java, or even Pascal from the 1970s. Commenters debate whether Go should add true, type-safe enums with exhaustiveness checking and safer serialization, or whether its minimalist, “just use ints and codegen/protobuf if needed” philosophy is an intentional and acceptable trade-off for simplicity and ease of use in typical web and backend work. The exchange also touches on broader questions of type safety, error handling, and how far a language should go in adding features versus keeping the core small and opinionated.
What “enums” even are (enums vs sum types)
- Several comments distinguish classic enums (finite sets of named constants, usually with integer backing and natural iteration/ordering) from algebraic/sum types (variants that can hold structured data and require pattern matching).
- Rust’s
enumis repeatedly cited as a sum type, not a “true enum” in the traditional sense, though others argue this distinction is not very useful in practice. - Some see attempts to collapse enums and sum types into one concept as confusing and conceptually harmful; others focus on their shared “choice among alternatives” use case.
Go’s current “enum” story
- Go lacks a dedicated enum keyword; idiom is
type T intplusconst (...)withiota. - Criticisms:
- Not a closed set; any underlying
intcan be constructed, including invalid values. - No built‑in string representation, exhaustiveness checking in
switch, or prevention of mixing unrelated “enum” types beyond the base type. iotais seen by some as dangerous for serialized values, since reordering constants silently changes numeric encodings.
- Not a closed set; any underlying
- Defenses:
- Many find
iotaconcise and very convenient, especially for bit flags. - Some argue Go’s “enums” are real enums (named constants of a distinct type) and that extra guardrails aren’t worth added complexity.
- Passing arbitrary ints is viewed by some as obviously a caller bug rather than a type-system failure.
- Many find
Workarounds and tools
- Common patterns: code generators (
go generate, third‑party tools, custom DSLs) to add stringification, JSON/Protobuf integration, and validation. - Protobuf enums are noted as a robust option if gRPC/Protobuf is already used, including safe evolution and cross‑language support.
Broader language‑design debate
- One side praises Go’s minimalism, fast builds, simple tooling, and “blue‑collar” suitability for REST/DevOps work.
- Another side calls the language primitive and “boneheaded” in its resistance to established features (generics, proper enums, sum types, null safety, richer type constraints).
- Comparisons highlight that many older or other languages (Pascal, Ada, Rust, MLs, C#, Java) have stronger enums or ADTs, with compile‑time exhaustiveness and better integration with type systems.
Error handling and optionality
- Some argue Go’s explicit
errorreturns are sane and treat errors as normal control flow. - Others prefer
Result/Either/Option‑style sum types and see Go’s lack of such constructs (plus nilability everywhere) as a major design gap.