enum is poorly defined

A

AngleWyrm

"The C++ Programming Language" by Bjarne Stroustrup, copyright 1997 by AT&T,
section 4.8 (pp 77):
"A value of integral type may be explicitly converted to an enumeration
type. The result of such a conversion is undefined unless the value is
within the range of the enumeration. For example:
enum flag { x=1, y=2, z=4, e=8 }; // range 0:15
flag f1 = 5; // type error: 5 is not of type flag
flag f2 = flag(5); // ok: flag(5) is of type flag and withing the range of
flag"

C++ Draft 2, December 1996, Section 7.2.9:
"An expression of arithmetic or enumeration type can be converted to an
enumeration type explicitly. The value is unchanged if it is in the range of
enumeration values of the enumeration type; otherwise the resulting
enumeration value is unspecified."

In both of these old references, an explicit conversion from integer (or
another enumeration) to an enumeration is allowed as long as the value falls
within the range of the enumeration. The first text even offers up the
obvious bug, and states that this is ok!

Consider what we are representing with an enumeration: At first glance, it
appears to be a set, useful for categorizing/subdividing some domain, with
the implicit purpose of later performing a switch/case or (less optimally)
if/then against the categories.

However,

enum TEST_T {FIRST = 0, SECOND = 0, THIRD = 100};
TEST_T eTest = FIRST, eSecondTest = SECOND;

if ( eTest == SECOND ){
cout << "faulty logic!" << endl;
}
if( eTest == eSecondTest ){
cout << "more confusion" << endl;
}

int iTest = 5;
eTest = (TEST_T) iTest; // which comes to what?
switch (eTest){
case FIRST:
case SECOND: // compiler catches what?: Duplicate case value
case THIRD:
cout << "success" << endl;
break;
default:
cout << "switch failure" << endl;
}

As you can see, several disasterous thinking processes are opened up.

Firstly, it doesn't seem to be in line with the mathematical concept of an
unordered set, nor does it seem to be a strictly ordered set, due to
duplicate values--which cause serious problems. Furthermore, explicit
conversion to an enumeration is allowed without having anything to do with
members of that enumeration! That's just absurd.

A tighter definition of what we are talking about when we refer to an
enumeration is in order, and thus I ask you, the programming world: What is
an enumeration?
 
V

Victor Bazarov

AngleWyrm said:
"The C++ Programming Language" by Bjarne Stroustrup, copyright 1997 by AT&T,
section 4.8 (pp 77):
"A value of integral type may be explicitly converted to an enumeration
type. The result of such a conversion is undefined unless the value is
within the range of the enumeration. For example:
enum flag { x=1, y=2, z=4, e=8 }; // range 0:15
flag f1 = 5; // type error: 5 is not of type flag
flag f2 = flag(5); // ok: flag(5) is of type flag and withing the range of
flag"

C++ Draft 2, December 1996, Section 7.2.9:
"An expression of arithmetic or enumeration type can be converted to an
enumeration type explicitly. The value is unchanged if it is in the range of
enumeration values of the enumeration type; otherwise the resulting
enumeration value is unspecified."

In both of these old references, an explicit conversion from integer (or
another enumeration) to an enumeration is allowed as long as the value falls
within the range of the enumeration. The first text even offers up the
obvious bug, and states that this is ok!

Consider what we are representing with an enumeration: At first glance, it
appears to be a set, useful for categorizing/subdividing some domain, with
the implicit purpose of later performing a switch/case or (less optimally)
if/then against the categories.

However,

enum TEST_T {FIRST = 0, SECOND = 0, THIRD = 100};
TEST_T eTest = FIRST, eSecondTest = SECOND;

if ( eTest == SECOND ){
cout << "faulty logic!" << endl;
}
if( eTest == eSecondTest ){
cout << "more confusion" << endl;
}

int iTest = 5;
eTest = (TEST_T) iTest; // which comes to what?
switch (eTest){
case FIRST:
case SECOND: // compiler catches what?: Duplicate case value
case THIRD:
cout << "success" << endl;
break;
default:
cout << "switch failure" << endl;
}

As you can see, several disasterous thinking processes are opened up.

Firstly, it doesn't seem to be in line with the mathematical concept of an
unordered set,

No. Who claimed it was supposed to?
nor does it seem to be a strictly ordered set,

Of course not. It's just a separate type with named constants.
due to
duplicate values--which cause serious problems. Furthermore, explicit
conversion to an enumeration is allowed without having anything to do with
members of that enumeration!

There are no _members_ in an enumeration.
That's just absurd.

That's just trolling.
A tighter definition of what we are talking about when we refer to an
enumeration is in order, and thus I ask you, the programming world: What is
an enumeration?

I think you're in a wrong newsgroup. You need either 'comp.programming'
for broader concept discussion or 'comp.std.c++' for discussions on _why_
certain things are the way they are in the language. 'comp.lang.c++' is
for discussions on 'how', not on 'why'. And its field of interest is
narrow: C++ language, not programming in general.

V
 
T

tom_usenet

On Tue, 10 Feb 2004 12:47:07 GMT, "AngleWyrm"

[SNIP]
In both of these old references, an explicit conversion from integer (or
another enumeration) to an enumeration is allowed as long as the value falls
within the range of the enumeration. The first text even offers up the
obvious bug, and states that this is ok!

What bug?
flag f2 = flag(5);
is fine, and expected. e.g.
flag f2 = flag(x | z);

It would be impossible to use an enum as a combinable set of flags
without this feature.
Consider what we are representing with an enumeration: At first glance, it
appears to be a set, useful for categorizing/subdividing some domain, with
the implicit purpose of later performing a switch/case or (less optimally)
if/then against the categories.

That is one use of it, yes. Another use is mentioned above. An
alternative to the flags use though is this:

enum Foo
{
A,
B,
C,
D,
MAXFOO
};

bitset<MAXFOO> foo;
foo[A] = 1;
foo[D] = 1;

if (foo[A])
{
//...
}
Firstly, it doesn't seem to be in line with the mathematical concept of an
unordered set, nor does it seem to be a strictly ordered set, due to
duplicate values--which cause serious problems. Furthermore, explicit
conversion to an enumeration is allowed without having anything to do with
members of that enumeration! That's just absurd.

A tighter definition of what we are talking about when we refer to an
enumeration is in order, and thus I ask you, the programming world: What is
an enumeration?

In C and C++, an enum is just a set of named constants with a
particular type. There is nothing stoping you from creating other
objects of this type. You could argue that this is less useful than it
could be, but it does enable certain idioms. The concept was created
in the C days - you might want to ask in a C experts group (perhaps
comp.std.c) for a good answer on the rationale behind the semantics.

You can of course create enum classes. It is harder to use them with
switch statements though, of course.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
R

Rob Williscroft

AngleWyrm wrote in
A tighter definition of what we are talking about when we refer to an
enumeration is in order, and thus I ask you, the programming world:
What is an enumeration?

In a philisophical sence I don't care.

In a C++ sence an enum type provides an named alias's for a integral
constants, it also gives those names a distinct type. Both properties
are *very* useful.

It does what it does. If you don't try to use it as something it is
not you don't have a problem.

The same is true for int, its an integer, but not *any* integer. Its
only an integer from a *very* limited range, understand that and
use it apropriatly and you have no problem. forget it and you get
undefined/unspecified behaviour.

int doesent meet the mathimatical concept of integer and enum
doesn't meet most peoples concept of enumeration.

But writing code *is* engeneering it *isn't* mathematics (or poetry).

If you want a better enumeration type (for your needs), you can
engineer one:

class your_enumeration
{
// start typing here.
};

Rob.
 
C

Clark Cox

AngleWyrm said:
"The C++ Programming Language" by Bjarne Stroustrup, copyright 1997 by AT&T,
section 4.8 (pp 77):
"A value of integral type may be explicitly converted to an enumeration
type. The result of such a conversion is undefined unless the value is
within the range of the enumeration. For example:
enum flag { x=1, y=2, z=4, e=8 }; // range 0:15
flag f1 = 5; // type error: 5 is not of type flag
flag f2 = flag(5); // ok: flag(5) is of type flag and withing the range of
flag"

C++ Draft 2, December 1996, Section 7.2.9:
"An expression of arithmetic or enumeration type can be converted to an
enumeration type explicitly. The value is unchanged if it is in the range of
enumeration values of the enumeration type; otherwise the resulting
enumeration value is unspecified."

In both of these old references, an explicit conversion from integer (or
another enumeration) to an enumeration is allowed as long as the value falls
within the range of the enumeration. The first text even offers up the
obvious bug, and states that this is ok!

I don't see a bug. Consider the following:

enum flag
{
bit1 = 1,
bit2 = 2,
bit3 = 4,
bit4 = 8
};

....

flag f = bit1 | bit3;

Representing bitfields in this manner is one of enum's many uses.
Consider what we are representing with an enumeration: At first glance, it
appears to be a set, useful for categorizing/subdividing some domain, with
the implicit purpose of later performing a switch/case or (less optimally)
if/then against the categories.

However,

enum TEST_T {FIRST = 0, SECOND = 0, THIRD = 100};
TEST_T eTest = FIRST, eSecondTest = SECOND;

if ( eTest == SECOND ){
cout << "faulty logic!" << endl;
}
if( eTest == eSecondTest ){
cout << "more confusion" << endl;
}

int iTest = 5;
eTest = (TEST_T) iTest; // which comes to what?

Anytime you have to explicitly cast something, that is a red flag
that should be paid careful attention.
switch (eTest){
case FIRST:
case SECOND: // compiler catches what?: Duplicate case value
case THIRD:
cout << "success" << endl;
break;
default:
cout << "switch failure" << endl;
}

As you can see, several disasterous thinking processes are opened up.

Firstly, it doesn't seem to be in line with the mathematical concept of an
unordered set, nor does it seem to be a strictly ordered set, due to
duplicate values--which cause serious problems. Furthermore, explicit
conversion to an enumeration is allowed without having anything to do with
members of that enumeration! That's just absurd.

Yes, but the conversion is explicit. It's no more absurd than
allowing other explicit casts:

const char aString[] = "A string";
const void *voidPtr = aString;
cout << (const char*)voidPtr << '\n';
A tighter definition of what we are talking about when we refer to an
enumeration is in order, and thus I ask you, the programming world: What is
an enumeration?

It's a group of integer constants an integer type able to represent
all of the values from the minimum constant to the maximum constant;
where's the confusion?
 
A

AngleWyrm

Under the heading "[29.19] If an enumeration type is distinct from any other
type, what good is it? What can you do with it?" the faq (
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.19 ) demonstrates
promoting an enum to an int, then explains that it is a one-way operation
implicitly, but can be explicitly overridden. It also states that enums
cannot be incremented. A good update to the faq might include the value of
compile-time type checking, which seems to be the only advantage that an
enum has over a set of #define statements.

Which brings up another question: Why bother with such a type check? Because
we want the values restricted to a given set? They aren't. They are allowed
to be in a range instead of discreet values, which makes the type check less
valuable.

With the ability to assign values along the way, the last value isn't
guaranteed to be the highest value, and it's physical position in the list
is psychologically misleading:

enum Foo{ A, B=10, C, D=2, MAXFOO };
bitset<MAXFOO> foo; // how many bits?
foo = 1; // where am I writing?

cout << "MAXFOO=" << int(MAXFOO) << endl;
cout << "size of foo: " << sizeof(foo) << endl;
cout << "foo: " << foo << endl;

If C++ were a perfect language, there would be no reason for the standards
commitee, or future versions of the language. And it looks to me that enums
have evolutionary potential.
 
A

AngleWyrm

Clark Cox said:
It's a group of integer constants an integer type able to represent
all of the values from the minimum constant to the maximum constant;
where's the confusion?

One the one hand, it is a selected group of itemized constants; a subset of
the possible range. On the other hand, the type refers to the range of those
constants.

If you allow a what-if scenario, the language could be more expressive. What
if the values were restricted exclusively to the enumeration, and further
that they be unique? It would then be possible to use an enumeration type
with the knowledge that it is *only* one of a specific set of values,
providing excellent support for switch/case and if/then usage.

The combination methods for flag usage could still be done with type
casting.

Furthermore, it would pave the way for the possibility of using
increment/decrement operators on enums.

And finally, casting a value to an enum could be done on a greaterThan
basis, so that it would always be one of the set.
 
T

tom_usenet

Under the heading "[29.19] If an enumeration type is distinct from any other
type, what good is it? What can you do with it?" the faq (
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.19 ) demonstrates
promoting an enum to an int, then explains that it is a one-way operation
implicitly, but can be explicitly overridden. It also states that enums
cannot be incremented. A good update to the faq might include the value of
compile-time type checking, which seems to be the only advantage that an
enum has over a set of #define statements.

That and namespacing (#defines are horrible - use namespace scope or
class static const variables if you want global constants).
Which brings up another question: Why bother with such a type check? Because
we want the values restricted to a given set? They aren't. They are allowed
to be in a range instead of discreet values, which makes the type check less
valuable.

But still potentially valuable, like any type safety.
With the ability to assign values along the way, the last value isn't
guaranteed to be the highest value, and it's physical position in the list
is psychologically misleading:

enum Foo{ A, B=10, C, D=2, MAXFOO };

What kind of idiom is that? The idiom:

enum Foo{ A, B, C, D, MAXFOO };

is quite well known, and explicitly involves relying on the implicit
values given to each constant.
If C++ were a perfect language, there would be no reason for the standards
commitee, or future versions of the language. And it looks to me that enums
have evolutionary potential.

Not without breaking lots of code. They're a C inherited feature - you
don't have to use them, and you can use a class based alternative if
you prefer. e.g.

template <class T>
class Enum
{
//allow lookup by name
static std::map<std::string, Enum<T>*> s_values;
static int s_value;
const char* const m_name;
int const m_value;

protected:
Enum(const char* name)
:m_name(name), m_value(s_value++)
{
//add this to map (check for duplicates)
}

public:

T const& get(const char* name) const;
//etc
int getValue() const;
};

class MyEnum: public Enum<MyEnum>
{
MyEnum(const char* name)
public:
static const MyEnum A;
static const MyEnum B;
static const MyEnum C;
static const MyEnum D;
};

const MyEnum MyEnum::A("A");
const MyEnum MyEnum::B("B");
const MyEnum MyEnum::C("C");
const MyEnum MyEnum::D("D");

etc.

This can even be combined with normal enums if you want switch
statement functionality and even macros if you want to drop some of
the boilerplate code.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
A

AngleWyrm

Ok, I'm working on it:

/*
* enum_t SPECIFICATION
*
* REASON FOR EXISTANCE
* The C++ enum keyword has problems, mostly for historical reasons,
* because of how it supports bit manipulations within a range.
* This effectively cripples the compiler's ability to issue a warning
* in cases where some of the enum's keywords are unhandled/misused.
*
* Further, in supporting a range, rather than the individual keywords,
* it becomes impossible to loop through a set of enumerated keywords,
* and thus the historical enum does not support ++ incrementing,
* and so cannot be used in for/while/loop constructs.
*
* Also, the historical enum is a logically fuzzy concept;
* it implies unsupported behavior. There is no guarantee
* that the values are unique, and yet if used in a switch/case statement,
* the compiler will choke on duplicate case values.
* If used in an if/then statement, unnoticed bugs can creep in.
*
* There is also no statement about the sequential status
* of items within an enum, and thus whether it is sortable.
* Yet enums often are used with a maxvalue terminator like so:
*
* enum eTerminated { A, B, C, MAX };
*
* this, to my mind, is confusing data with function,
* a chore better relegated to a container.size() function.
*
* DEFINITION
* enum_t defines a stricter version of the enum keyword,
* with the express purpose of supporting a set of mutually exclusive
values.
* Because of this, it is possible to increment/loop through an enum_t.
*
* The enum_t consists only of the keyword values defined within it;
* Values outside the set are not a part of the enumeration.
* As such, casting to an enum_t is a conversion to one of the
keyword-values.
*
* Due to unique values, the enum_t is also a sequential container,
* and therefore sortable.
*/

Any comments / criticisms / suggestions?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Trouble calling a function with enum parameter 3
Enum to String 6
enum 9
Something is wrong 1
one enum is a subset of another 10
Enum oddity 14
ANN: Python 3 enum package 0
Command Line Arguments 0

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top