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