Good union types in Go would probably need types without a zero value
Union / Sum Types vs Go’s Zero Values
- Central question: can Go have “good” union/sum types without breaking its “every type has a zero value” design.
- Some argue zero values for unions are either useless (just memory packing tricks) or dangerous / confusing.
- Others suggest pragmatic compromises: zero value = first variant, or zero value = nil/interface-like “no value”, even if slightly “stupid” but consistent with Go’s other rough edges.
- Concern: choosing “first variant as default” breaks commutativity (
A|BvsB|Adiffer) and can be a footgun.
Error Handling and Exhaustiveness
- Several commenters want sum types mainly to improve error handling:
- Avoid repetitive
switch/errors.Is/string-matching patterns. - Get compile-time guarantees of “handled all error cases” and easy refactoring when error variants change.
- Avoid repetitive
- Comparisons to Rust, Scala (ZIO/Cats Effect), Zig, Nim:
- These offer more precise error typing or effect systems, but still don’t perfectly answer “show me all possible errors here.”
- Some find Rust’s error ergonomics disappointing in practice; sum types can demand lots of boilerplate and wrapping.
Runtime and GC Constraints
- Big technical objection: Go’s concurrent GC needs to know where pointers are.
- A tagged union whose active variant changes could change which fields are pointers, racing with the GC if done naïvely.
- Go previously changed interface representation to avoid similar GC races; unboxed tagged unions might require deep runtime redesign.
- Boxing every variant (like interfaces) is feasible but adds allocations and undermines performance motivations.
Expressiveness vs Simplicity
- Many feel Go’s type system is too weak for serious domain modeling (e.g., “make invalid states unrepresentable”; non-zero-only types).
- Others report very high productivity with Go and view stronger type systems as added cognitive load, especially for large teams of relatively new engineers.
- Tension: minimal core language vs pushing complexity into codebases (custom patterns, libraries, boilerplate).
Did Go ‘Ignore’ PL Research?
- Some say Go failed to adopt 40–50 years of known ideas (sum types, richer generics, algebraic data types).
- Counterpoint: adoption, readability, tooling, GC, and compatibility constraints justify caution; features can’t just be copied from ML/OCaml.
- Go’s compatibility promise and lack of a story for evolving enums/sums without breaking users is cited as a blocker.
Workarounds and Partial Solutions
- Current practice: interfaces plus type switches; sealed interfaces with unexported methods; tooling for exhaustiveness checks.
- Proposed syntactic sugar: special
option/result-like constructs usingmakeand type assertions; would still panic on misuse, consistent with other Go nil/zero traps. - Some prefer to “just use another language”; others note they’re constrained by employer choices, so they keep pushing for better features in Go.