(moving http://goo.gl/ZISWwN to this group)

On 4/7/14, 3:41 PM, w0rp wrote:
Yeah, I've seen this happen before. I think we could actually introduce
a little more type safety on enums without a great deal of breakage. It
would be nice to have a final switch give you as much of a guarantee
about what it's doing as it can.

People use enums for things such as:

1. A discrete set of categorical values:

enum State { initial, waiting, running, done }

That's probably the most common use, and the one that prompted the moniker "enum(eration)".

On these, virtually no arithmetic makes any sense. At most, some notion of State successor(State) and State predecessor(State) may be sensible. It would return the next/previously naturally occurring discrete value, and would either throw, assert, or saturate at limits.

2. A collection of power-of-two flags that can be combined with "or" and picked apart with "and".

enum AccountFlags { active = 1, overdrawn, hasDiscount = 4, primary = 8 }

Often, people who define these enums offer names for frequently-encountered combinations of these flags:

enum AccountFlags { active = 1, overdrawn, hasDiscount = 4, primary = 8, regular = active | primary }

For these kinds of flags, arithmetic doesn't make sense, only bitwise operations: "|", "&", "^", and "~". A small algebra would be defined for these operations.

3. A discrete set of categorical values, not all of which are named:

enum UserID : ulong { nobody, expired = ulong.max }

There would be no arithmetic/logic for such enums - they are only to express categories. Comparisons for equality are needed; comparisons for inequality may or may not be needed.

4. A "clone" of a type (usually numeric) that's generally used as a helper for better typing.

enum Kilogram : double {}
enum Percent {}

All usual arithmetic is supposed to work. The enum acts as a subtype of its base type.

5. Various combinations of the above, for example flags combined with masks:

enum AccountFlags { codeMask = 7, active = 8, overdrawn = 16, hasDiscount = 32, primary = 64 }

(The account would start with a 3-bit code.) For such complex/irregular uses it may make sense to require casting to the base type of the enum before carrying general operations.

==========================

The current design is loose enough to accommodate all of the above uses, probably too loose because it allows a bunch of nonsensical code to compile. There are several questions to ask ourselves:

1. Is the current design damaging enough (= allows enough wrong/buggy code to pass through) to warrant a breaking tightening?

2. To what extent can library-based approaches help?

3. What is the priority of improving enums in the larger picture of other things we must do?


Andreiu

Reply via email to