enum

Mike none at none.com
Fri Apr 11 16:26:33 PDT 2014


On Friday, 11 April 2014 at 05:52:38 UTC, Walter Bright wrote:
>
> Bit flag usage is often more complex than just bit flags. 
> Sometimes there are "unions" of different meanings for some bit 
> sequences depending on the state of other bits.
>
> Besides, bit flags aren't the only instance of "an integral 
> type where some values have names". The Color enum is another 
> one.

But they are not integral types.  They are only modeled that way 
because the language doesn't have anything better.

** NOTE **
The following is not a proposal; it is admittedly naive and very 
incomplete. I'm just trying to provoke some thought.  The point 
being that enum is too often used for things it isn't well suited 
for because the language lacks a more correct means.  Provide a 
more correct means, and users will migrate away from enum and the 
usage of enum becomes more well defined or potentially even 
deprecated.

**********************************
* bitflags
**********************************
Consider...
enum Policy
{
   read,
   write,
   readwrite
}

What is the value of 'read'?  I don't mean the value the compiler 
assigned to it, I mean the intrinsic value of 'read'.  And what 
is readwrite?  Is it 'read + write', 'read ~ write', 'read | 
write'?

All of these questions are nonsense because 'read', 'write', and 
'readwrite' have no value.  They are just given an arbitrary 
value by the compiler so they can be distinguished from one 
another.

'Policy' is really an enumeration of sets, and I mean the 'set 
theory' kind of sets.  We have the read set, the write set, and 
the union of the read set and the write set, aka the readwrite 
set.  What's needed is a way to tell the compiler that we want a 
set of bits and not integral values, so it can enforce 
appropriate usage.

Maybe something along these lines:
bitflags!(2) Policy
{
     read = 1,
     write = 2,
     readwrite = read | write,
}

Because we told the compiler that the type is a bitflags, and not 
just some arbitrary integral values, it can enforce certain rules 
about its usage.

1.  Arithmetic (+, -, *, /) is invalid.  Policy.read + 
Policy.write is nonsense.
2.  Comparison operations (<, >, <=, >=) are invalid.  Again the 
value is arbitrary and meaningless.
2.  Set operations (|, &, ^, ~) are valid using the bitwise 
operators as substitues for ∪,∩, etc... Policy.read | 
Policy.write creates a new set that is equal to the readwrite set.
4.  Equality operators (==, !=) are valid.
5.  If you want to expose the value in memory and use it as an 
integral value, you must cast it to the integral value.
6.  If you want to use an integral value as a bitflags, you must 
cast it to bitflags

**********************************
* ordinal
**********************************
 From wikipedia (http://en.wikipedia.org/wiki/Ordinal_data): In 
statistics, ordinal data is a statistical data type consisting of 
numerical scores that exist on an ordinal scale, i.e. an 
arbitrary numerical scale where the exact numerical quantity of a 
particular value has no significance beyond its ability to 
establish a ranking over a set of data points.

Again, enum isn't well suited for this because it's too vague. 
Something more specific is needed.

//Just so you know ARM Cotex-M model's interrupt priority this 
way.
ordinal Priority : ubyte
{
     Low = 2,
     Medium = 1,
     High = 0
}

Here, again the value is arbitrary.  We told the compiler it's an 
ordinal, so the ranking is actually the lexical order in which 
they appear (low to high). So High > Low == true despite the 
arbitrary value assigned by the user/compiler. The value only 
serves as a way to distinguish one from the other in memory.

1.  Comparison operations (<, >, <=, >=) are valid in order to 
compare the ranking.  Comparison is on lexical order.  Comparing 
with integral type is invalid without a cast.
2.  Equality operators (==, !=) are valid.
3.  Could potentially use ++ and -- to increase or decrease the 
ranking.
4.  If you want to expose the value in memory and use it as an 
integral value, you must cast it to the integral value.
5.  If you want to use an integral value as a Policy, you must 
cast it to Policy, and if there is no valid policy with that 
value, it throws an exception.

If I've articulated the general principle well enough, I'm sure 
the language designers could run with this and design something 
quite elegant with high utility.


More information about the Digitalmars-d mailing list