API design note: Beware of adding an "Other" enum value
Protobuf, “UNSPECIFIED=0”, and default semantics
- Several comments compare the article’s “Other” warning with protobuf’s guidance that enum value 0 should be “UNSPECIFIED/UNKNOWN”.
- Consensus: “unspecified/unknown” (default, unset, no semantics) is different from “other” (a real, specified-but-unrecognized value).
- Protobuf best practice: never assign business meaning to the default value; treat it like null and convert to stricter internal types that don’t carry “unknown” into business logic.
- Proto’s behavior around unknown enum values is nuanced and differs for open vs closed enums and across languages, creating confusion and some dislike for the design.
Open vs closed enums and versioning
- A core tension: many domains (sports, gender, document types, hardware uarch, A/B experiments) evolve, so enums are effectively open-ended over time.
- For distributed systems and mixed-version deployments, consumers must be prepared for unknown values (new enum variants), or upgrades and rollbacks break.
- Some argue you should design schemas with explicit “unknown/other” (or generic codes per category) to allow n and n+1 versions to coexist.
- Others counter that if you can update all components in lockstep or use per-version shims, you can keep enums truly closed and rely on exhaustive handling.
Language mechanisms: Rust, Swift, others
- Rust’s
#[non_exhaustive]forces callers to include a default match arm, enabling library authors to add variants without breaking consumers. - Supporters say this lets each consumer choose whether new variants become compile errors (via lints) or fall into a default case.
- Critics dislike that required defaults can silently swallow new cases that should be handled explicitly.
- Swift’s
@frozenplusdefaultvs@unknown default, and TypeScript patterns, aim for a middle ground: forward compatibility plus warnings when new cases appear. - Some note that in C/C++ enums are just ints and can hold out-of-range values (even UB), so enums are already “open” in practice.
Design patterns and alternatives to Other
- Suggested patterns:
- Use
Unknown/Invalid = 0as default, but don’t allow it in validated business logic. - Use optional/nullable enums to distinguish “not provided” from “unrecognized”, sometimes with a raw-value accessor.
- Document enums as open-ended and treat unrecognized values as “other” at the edges, without a literal
Othermember. - Avoid enums for evolving lists; use strings plus a known-values table or richer types (e.g., enum variants plus a free-form field), while avoiding invalid combined states.
- Use
General attitudes toward enums
- Some engineers see enums as dangerous in public or cross-team APIs because extending them often breaks consumers.
- Others emphasize that with careful design (open-ended treatment, unknown codes, reserved ranges, or non-exhaustive features) enums remain useful, but “Other” must be handled with clear semantics and strong tooling.