Consider the following API:
enum class WidgetFlavor
{
Vanilla,
Chocolate,
Strawberry,
Other,
};
WidgetFlavor GetWidgetFlavor(HWIDGET widget);
The idea here is that Widgets come in three flavors today, but we might add new flavors in the future, so we add an Other value to cover any future flavors.
This is a problem.
Suppose we do indeed add a new flavor Mint in the next version.
enum class WidgetFlavor
{
Vanilla,
Chocolate,
Strawberry,
Other,
Mint,
};
What flavor should you report if somebody calls GetÂWidgetÂFlavor and the widget is mint?
If you return WidgetFlavor::, then this will confuse code written with the Version 1 API, because they expected to get Other for anything that isn’t vanilla, chocolate, or strawberry. The word “other” means “not mentioned elsewhere”, so the presence of an Other logically implies that the enumeration is exhaustive.
On the other hand, you obviously should return WidgetFlavor:: because that’s why you added the value to the enum in the first place!
My recommendation is not to have an Other at all. Just document that the enumeration is open-ended, and programs should treat any unrecognized values as if they were “Other”. Any code that uses this enumeration will therefore put all unrecognized values into an app-defined “Other” category on their own. Now you can add Mint: New code will put minty widgets in a “Mint” category, and old code will continue to put them in the app=defined “Other” category.
If you are doing C++ then you should specify the type of enum base, if you are doing this trick.
If you are doing C then it’s best to add MaximumValue =2147483647 to ensure that different compilers and platforms wouldn’t change the layout of your class after you would add 256th flavor.
Because otherwise, according to the C/C++ standard, adding Mint to Vanilla, Chocolate, and Strawberry is legal, but adding Watermelon to that is no longer legal!
Rust has `#[non_exhaustive]` for this. https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute
I like the idea of an [Open] attribute to apply to enums.. similar to [Flags]. Documentation isn’t enough – there are so many de/serialization and ORM etc frameworks, that will throw exceptions when they see “flavor: 7”.
And this would help settle, once and for all, the ageless debate over whether or not it’s a breaking-change to add a value to an enum.
In the Apache Avro schema language, an enum type can have a default value, to which any unrecognized values are mapped during deserialization. This feature improves compatibility if a message is written using a newer version of the schema but is then read by software that uses an older version. Unlike C# and C++, Avro does not support casting arbitrary integers to an enum type.