enum

Jonathan M Davis jmdavisProg at gmx.com
Sat Apr 12 06:32:49 PDT 2014


On Saturday, April 12, 2014 05:59:29 Jonathan M Davis wrote:
> On Friday, April 11, 2014 19:52:58 Andrei Alexandrescu wrote:
> > On 4/11/14, 6:59 PM, Jonathan M Davis wrote:
> > > I take issue with the idea that it makes sense to have any variables of
> > > an
> > > enum type that isn't one of the values enumerated in the enum.
> > 
> > I explained the possible situations in the original post of this thread.
> > E.g. one may be unable to enumerate all user IDs, but may be compelled
> > to enumerate a few remarkable ones and ascribe user IDs a separate type.
> > -- Andrei
> 
> And what would the purpose by of giving them their own type? If the enum
> doesn't enumerate all of the values, then you're clearly going to be using
> other values with it, meaning that any restrictions on setting a variable to
> those other values is going to be a problem (as is currently the case with
> enums - assignment and initialization are protected against non-enumerated
> values). You'd just end up with a enum type which is effectively an alias
> for the enum's base type except that assigning it non-enumerated values
> requires casting, and you can overload a function on the enumerated values
> vs the non- enumerated ones (or at  least, non-enumerated ones which aren't
> cast to the enum type) by overloading a function on the enum type and its
> base type - which would be highly bug-prone IMHO.
> 
> In such a case, the enum type is adding nothing but a name, so why not just
> use an alias - especially when even the minimal protections that enum types
> currently have against other values will get in the way of using it for non-
> enumerated values. And that would be particularly painful in your example,
> because the enum only had UserID.nobody and UserID.expired, meaning that
> nearly ever time you initialized or assigned to a UserID, you'd have to
> cast. It sounds like what you really want/need is an alias along with an
> enum with the constants for nobody and expired, but given how enums work
> even now (without the full protections that I think they should have),
> actually using the enum type for user IDs is just going to cause problems.

On further reflection, I think that having enum and final enum would make 
sense as long as enum were changed so that it introduced an alias rather than 
a new type. A new type just doesn't make sense if you're not listing all the 
values - especially because the few protections that the compiler has against 
giving an enum a non-enumerated value just get in the way of that use case - 
whereas if the enum _is_ intended to enumerate all its values, it makes sense 
that it would introduce a new type that was protected against having it set to 
non-enumerated values. So,

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

would then introduce an alias UserID for ulong as well as namespace the 
constants nobody and expired, but there would be no new type introduced, so it 
would not protect against being assigned non-enumerated values, and it would 
not affect overloading. It also wouldn't work with final switch.

final enum State { initial, waiting, running, done }

would then be the same as

enum State { initial, waiting, running, done }

is now except that the compiler would actually guarantee that no variable of 
type State could have a non-enumerated value unless a cast was used (so any 
operation which wasn't guaranteed to result in an enumerated value would 
result in a value of the base type rather than the enum type). And of course, 
it would then work properly with final switch, because it couldn't have a non-
enumerated value unless you forced it with a cast.

With that separation, we can then separate out the enums which are really 
enumerations and those which are really just a group of related constants. But 
I think that the key thing is that introducing a new type really doesn't make 
sense if it's just a group of related constants. Introducing an alias is fine 
- but a new type just doesn't make sense IMHO.

For better or worse, if we went this route, we'd end up with something closer 
to C++11's enums and enum classes, though unlike enum classes, our final enum 
would implicitly convert to its base type, and operations on it which weren't 
guaranteed to result in a valid enum value would result in the base type, 
whereas it's my understanding that you have to overload operators to get any 
of that working at all with enum classes.

- Jonathan M Davis


More information about the Digitalmars-d mailing list