Topic: enums as bit patterns.
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Thu, 14 Jul 1994 11:03:22 +0000 Raw View
In article <300gck$dub@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
[stuff deleted]
>Is it possible do use the namespace of a class X where the enum is declared,
>so that I can use the enumerators without X:: ?
>
> class TrafficLight {
> public:
> enum Color { Red, Yellow, Green };
> Color state;
> };
>
> class Intersection {
> TrafficLight light[4];
> public: bool invariant ()
> { using TrafficLight; // <== ???
>
> if(light[0].state==Green)
> return light[1]!=Green && light[3]!=Green;
> if(light[2].state==Green)
> return light[1]!=Green && light[3]!=Green;
> if(light[1].state==Green)
> return light[0]!=Green && light[2]!=Green;
> if(light[3].state==Green)
> return light[0]!=Green && light[2]!=Green;
> return true;
> }
> };
>If one can't I would tend to declare enum Color at global scope
>to avoid the unhandy and difficult-to-read:
>
> if(light[0].state==TrafficLight::Green)
> return light[1]!=TrafficLight::Green && light[3]!
>=TrafficLight::Green;
> ...
[stuff deleted]
Yes, I believe that this is correct use of using wrt classes, since they
define a namespace. This would open up all the static decls and types in
the given class.
--
Kevlin A P Henney
synonymicon is another word for thesaurus
Author: jimad@microsoft.com (Jim Adcock)
Date: Thu, 14 Jul 1994 17:20:23 GMT Raw View
In article <CsotBs.Huo@borland.com> pete@genghis.interbase.borland.com (Pete Becker) writes:
| But guess what? It doesn't work if FLAGS1 can hold values other than
|those that I defined it to hold. So your intuition is different from my
|intuition, which means that neither is a good guide to how these things should
|work.
My intuition is that the committee ought to be less casual about breaking
existing programs and programming techniques. Is this suppose to be a
*standardization* effort, or what?
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 15 Jul 1994 14:51:20 GMT Raw View
In article <774183802snz@wslint.demon.co.uk>, kevlin@wslint.demon.co.uk (Kevlin Henney) writes:
|> In article <300gck$dub@hpsystem1.informatik.tu-muenchen.de>
|> schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
|>
|> [stuff deleted]
|> >Is it possible do use the namespace of a class X where the enum is declared,
|> >so that I can use the enumerators without X:: ?
|> >
|> > class TrafficLight {
|> > public:
|> > enum Color { Red, Yellow, Green };
|> > Color state;
|> > };
|> >
|> > class Intersection {
|> > TrafficLight light[4];
|> > public: bool invariant ()
|> > { using TrafficLight; // <== ???
|> >
|> > if(light[0].state==Green)
|> > return light[1]!=Green && light[3]!=Green;
|> > if(light[2].state==Green)
|> > return light[1]!=Green && light[3]!=Green;
|> > if(light[1].state==Green)
|> > return light[0]!=Green && light[2]!=Green;
|> > if(light[3].state==Green)
|> > return light[0]!=Green && light[2]!=Green;
|> > return true;
|> > }
|> > };
|> [stuff deleted]
|>
|> Yes, I believe that this is correct use of using wrt classes, since they
|> define a namespace. This would open up all the static decls and types in
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|> the given class.
This is good news. About half a year ago I asked a bunch of questions about
namespaces. Due to my understanding of the answers I thought it was
NOT allowed to use (the namespace of) a class ("using TrafficLight;").
Such a missing orthogonality did disappoint me.
Now I am not sure any more: is it possible to use a class and thus open up
all the static decls and types, or not?
Now it seems at least that I am not the only one who has the intuitive
believe that this is / should be allowed. Thank you, Kevlin.
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
Author: dag@control.lth.se (Dag Bruck)
Date: 18 Jul 1994 14:23:53 GMT Raw View
>>>>> "Jim" == Jim Adcock <jimad@microsoft.com> writes:
Jim> My intuition is that the committee ought to be less casual about
Jim> breaking existing programs and programming techniques. Is this
Jim> suppose to be a *standardization* effort, or what?
If my memory serves me correctly, the discussion has refered to the
difference between C and C++ wrt to enumerations. The "broken"
existing programs are C programs that need modification to compile as
C++ programs.
Please note that these programs are already "broken" in current C++ as
defined in the ARM. The standardization committee has not changed the
rules regarding enumerations in such a way that existing C++ program
cease to compile.
- Dag Bruck
Author: miket@world.std.com (Michael Trachtman)
Date: Sat, 9 Jul 1994 04:23:49 GMT Raw View
In an article, Dag Bruck (dag@control.lth.se) wrote:
: If you just want to do bit operations without any added effort, why
: not use integers? Integers are there and you don't have to code
: anything.
Because, we want symbolic constants and good static type checking.
If enums did what we intuitively expect them to do, namely
work like 'C' with the addition of strict type checking, then we would be
happy.
So we could write:
enum FLAGS1 { READ = 0x01, WRITE = 0x02 };
enum TOPPINGS { CHERRY = 0x01, CREAM = 0x02, CHOCOLATE = 0x04 };
FLAGS1 f = READ | WRITE; // ok, all of the same type.
TOPPINGS t = CHERRY | CHOCOLATE; // ok, all of the same type.
f |= CREAM; // error - type mismatch.
if ( f & CHERRY) ; // error - type mismatch.
This (i.e. strong type safety) can't be done with ints
and #define (or const int).
If enums did what we intuitively expect them to do,
then we would get strong type safety, while maintaining
backward compatability with the vast majority of 'C' code which
uses enums in this way.
Author: pete@genghis.interbase.borland.com (Pete Becker)
Date: Sat, 9 Jul 1994 19:11:51 GMT Raw View
In article <Csno7q.AK4@world.std.com>,
Michael Trachtman <miket@world.std.com> wrote:
>In an article, Dag Bruck (dag@control.lth.se) wrote:
>
>: If you just want to do bit operations without any added effort, why
>: not use integers? Integers are there and you don't have to code
>: anything.
>
>Because, we want symbolic constants and good static type checking.
>
>If enums did what we intuitively expect them to do, namely
>work like 'C' with the addition of strict type checking, then we would be
>happy.
>
>So we could write:
>
>enum FLAGS1 { READ = 0x01, WRITE = 0x02 };
>enum TOPPINGS { CHERRY = 0x01, CREAM = 0x02, CHOCOLATE = 0x04 };
>
I'd also like to write
ostream& operator << ( ostream& out, FLAGS1 flag )
{
switch( flag )
case READ:
out << "READ";
break;
case WRITE:
out << "WRITE";
break;
return out;
}
But guess what? It doesn't work if FLAGS1 can hold values other than
those that I defined it to hold. So your intuition is different from my
intuition, which means that neither is a good guide to how these things should
work.
-- Pete
Author: miket@world.std.com (Michael Trachtman)
Date: Sun, 10 Jul 1994 06:41:07 GMT Raw View
In an article, Pete Becker (pete@genghis.interbase.borland.com) wrote:
: In article <Csno7q.AK4@world.std.com>,
: Michael Trachtman <miket@world.std.com> wrote:
: >If enums did what we intuitively expect them to do, namely
: >work like 'C' with the addition of strict type checking, then we would be
: >happy.
: >
: >enum FLAGS1 { READ = 0x01, WRITE = 0x02 };
: >enum TOPPINGS { CHERRY = 0x01, CREAM = 0x02, CHOCOLATE = 0x04 };
: >
: I'd also like to write
: ostream& operator << ( ostream& out, FLAGS1 flag )
: {
: switch( flag )
: case READ: out << "READ"; break;
: case WRITE : out << "WRITE"; break;
: return out;
: }
: But guess what? It doesn't work if FLAGS1 can hold values other than
: those that I defined it to hold. So your intuition is different from my
: intuition, which means that neither is a good guide to how these things should
: work.
The point was that it should work just like 'C', with the addtion
of strict type checking.
Your "intuition" is not based on what 'C' already does.
Michael T.
Michael T.
Author: bagpiper@netcom.com (Michael Hunter)
Date: Sun, 10 Jul 1994 17:55:37 GMT Raw View
Michael Trachtman (miket@world.std.com) wrote:
: In an article, Dag Bruck (dag@control.lth.se) wrote:
: If enums did what we intuitively expect them to do,
: then we would get strong type safety, while maintaining
: backward compatability with the vast majority of 'C' code which
: uses enums in this way.
My intuition (and other languages) says that enums only introduce an
identifier into the namespace. Numerics on enums should be
undefined!!! Your intuition has been biased via using c.
Has leaving enums with the c semantics and syntax and adding
"super-enums" with C++ syntax and semantics ever been considered?
The it-makes-the-language-that-much-larger problem is obvious, but
it does provide for growth while providing for backwards
compat.
mph
--
* Michael Hunter bagpiper@netcom.com or QUICS: mphunter
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 11 Jul 1994 18:40:15 GMT Raw View
[kevlin@wslint.demon.co.uk (Kevlin Henney):]
>... In C++ enums are typically used w/i classes to
>represent some aspect of that class, rather than roaming freely in wild
>badlands of the global namespace. I'm not sure that another level of
>namespace nesting would help things, but if you want it you don't have
>to change the language:
>
> namespace Colour
> {
> enum Type
> {
> Red,
> Green,
> Blue
> };
> };
This is a usually suggested 'workaround' in discussions were people
complain about enumerators. But this would REQUIRE that everyone
writing enums that should be used #included be others puts every enum
into a namespace. Otherwise if you #include two different headers
which happen to define the same enumerator there is a conflict at the
point of declaration and you can't do anything about it.
The point is that there is no need to forbid overlapping enumeratornames
as it is always possible to exactly qualify which enumerator
you mean when ambiguities occure. This is possible(thinkable) without
introducing wrapper-namespaces and without inventing new syntax
or new namelookup-rules or new contextsensitivities.
I would realy like to understand it but I can't see what this restriction
is good for (in the current state of C++). Please explain it to me if
you know!
I'm not so sure about namespaces but the suggested 'workaround' (IMHO)
has some disadvantages:
namespace N1 { enum E1 { x }; }; // defines N1::x
namespace N2 { enum E2 { x }; }; // defines N2::x
(1) Either I use E1, E2 and x with a N1:: or N2:: every time
(this is too annoying)
(2) Or I have to explicitly write "using N1; using N2;"
(or was it: "using namespace N1; ..." ?)
(3) This introduces new (IMO unnecessary) identifers N1, N2
which (nearly) mean the same as E1, E2
(e.g. 'the type of colors' vs 'the namespace of colors')
(4) The ambigouity of x (while "using" N1 and N2) can be resolved
by N1::x or N2::x respectivly. At this point the distinction
between the namespace and the enum-type is made obvious.
But this is a confusing distinction:
E1 e = N1::x;
(IMHO E1 e = E1::x; is more intuitive)
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Tue, 12 Jul 1994 08:08:22 +0000 Raw View
In article <2vs3mf$lmj@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>[kevlin@wslint.demon.co.uk (Kevlin Henney):]
>>... In C++ enums are typically used w/i classes to
>>represent some aspect of that class, rather than roaming freely in wild
>>badlands of the global namespace. I'm not sure that another level of
>>namespace nesting would help things, but if you want it you don't have
>>to change the language:
>>
>> namespace Colour
>> {
>> enum Type
>> {
>> Red,
>> Green,
>> Blue
>> };
>> };
>
>This is a usually suggested 'workaround' in discussions were people
>complain about enumerators. But this would REQUIRE that everyone
>writing enums that should be used #included be others puts every enum
>into a namespace. Otherwise if you #include two different headers
>which happen to define the same enumerator there is a conflict at the
>point of declaration and you can't do anything about it.
Workarounds imply that there is a problem - in this case there is no
problem & so this isn't a workaround ;-)
>The point is that there is no need to forbid overlapping enumeratornames
>as it is always possible to exactly qualify which enumerator
>you mean when ambiguities occure. This is possible(thinkable) without
>introducing wrapper-namespaces and without inventing new syntax
>or new namelookup-rules or new contextsensitivities.
>I would realy like to understand it but I can't see what this restriction
>is good for (in the current state of C++). Please explain it to me if
>you know!
Take it back a step & think about what you are asking: what would
you expect the compiler to do with the following global decls?
const int X = ...;
const char X = ...;
I would expect an error, therefore applying the same principle
enum A { X };
enum B { X };
should, & does, cause the compiler to cough up an error.
>I'm not so sure about namespaces but the suggested 'workaround' (IMHO)
>has some disadvantages:
>
> namespace N1 { enum E1 { x }; }; // defines N1::x
> namespace N2 { enum E2 { x }; }; // defines N2::x
>
>(1) Either I use E1, E2 and x with a N1:: or N2:: every time
> (this is too annoying)
>(2) Or I have to explicitly write "using N1; using N2;"
> (or was it: "using namespace N1; ..." ?)
/1/ & /2/ are the point of namespaces.
>(3) This introduces new (IMO unnecessary) identifers N1, N2
> which (nearly) mean the same as E1, E2
> (e.g. 'the type of colors' vs 'the namespace of colors')
>(4) The ambigouity of x (while "using" N1 and N2) can be resolved
> by N1::x or N2::x respectivly. At this point the distinction
> between the namespace and the enum-type is made obvious.
> But this is a confusing distinction:
> E1 e = N1::x;
> (IMHO E1 e = E1::x; is more intuitive)
namespace Colour
{
enum Colour
{
Red,
Green,
Blue
};
};
using Colour::Colour;
...
Colour TrafficLight = Colour::Red;
Again I would say that there is less use for enums in C++ than in C, and
so making them overly important is not useful. When most people use enums
in C++ it is generally to implement some feature of a class, & hence they
are already embedded in a useful namespace.
Solutions are only reqd for problems - in the absence of a problem might
I suggest that no solution is reqd?
--
Kevlin A P Henney
repeat 3 echo there\'s no place like ~
Author: jones@cais.cais.com (Ben Jones)
Date: 12 Jul 1994 13:11:27 GMT Raw View
Michael Trachtman (miket@world.std.com) wrote:
: In an article, Pete Becker (pete@genghis.interbase.borland.com) wrote:
: : In article <Csno7q.AK4@world.std.com>,
: : Michael Trachtman <miket@world.std.com> wrote:
: : >If enums did what we intuitively expect them to do, namely
: : >work like 'C' with the addition of strict type checking, then we would be
: : >happy.
: : >
: : >enum FLAGS1 { READ = 0x01, WRITE = 0x02 };
: : >enum TOPPINGS { CHERRY = 0x01, CREAM = 0x02, CHOCOLATE = 0x04 };
: : >
: : I'd also like to write
: : ostream& operator << ( ostream& out, FLAGS1 flag )
: : {
: : switch( flag )
: : case READ: out << "READ"; break;
: : case WRITE : out << "WRITE"; break;
: : return out;
: : }
: : But guess what? It doesn't work if FLAGS1 can hold values other than
: : those that I defined it to hold. So your intuition is different from my
: : intuition, which means that neither is a good guide to how these things should
: : work.
I don't see your point. If you use int, you have even more values it could
hold that don't do anything. The above example would at least allow you to
say:
out << READ;
out << WRITE;
without worrying about whether READ or WRITE might mean something totally
different in another context.
If you should happen to say:
out << READ+2;
out << (FLAGS1)10;
you deserve what you get but you're probably not going to say that anyway.
Ben Jones
Author: jones@cais.cais.com (Ben Jones)
Date: 12 Jul 1994 13:18:11 GMT Raw View
Michael Hunter (bagpiper@netcom.com) wrote:
: Michael Trachtman (miket@world.std.com) wrote:
: : In an article, Dag Bruck (dag@control.lth.se) wrote:
: : If enums did what we intuitively expect them to do,
: : then we would get strong type safety, while maintaining
: : backward compatability with the vast majority of 'C' code which
: : uses enums in this way.
: My intuition (and other languages) says that enums only introduce an
: identifier into the namespace. Numerics on enums should be
: undefined!!! Your intuition has been biased via using c.
If they fixed enums as suggested, you can still do what you think is
intuitive and not use the new feature. I still think people might
want to say:
enum Alpha { A,B,C,...,Z };
for (Alpha a=A;e<=Z;e++) ...
to iterate over a set of enumerators.
Ben Jones
Author: jones@cais.cais.com (Ben Jones)
Date: 12 Jul 1994 13:28:27 GMT Raw View
Ulf Schuenemann (schuenem@Informatik.TU-Muenchen.DE) wrote:
: (IMHO E1 e = E1::x; is more intuitive)
Being able to say:
E1 e = x;
is even more intuitive.
Ben Jones
jones@arsoftware.arclch.com
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 13 Jul 1994 10:33:26 GMT Raw View
kevlin@wslint.demon.co.uk (Kevlin Henney) wrote:
> >The point is that there is no need to forbid overlapping enumeratornames
> >as it is always possible to exactly qualify which enumerator
> >you mean when ambiguities occure. This is possible(thinkable) without
> >introducing wrapper-namespaces and without inventing new syntax
> >or new namelookup-rules or new contextsensitivities.
> >I would realy like to understand it but I can't see what this restriction
> >is good for (in the current state of C++). Please explain it to me if
> >you know!
>
> Take it back a step & think about what you are asking: what would
> you expect the compiler to do with the following global decls?
>
> const int X = ...;
> const char X = ...;
>
> I would expect an error, therefore applying the same principle
>
> enum A { X };
> enum B { X };
>
> should, & does, cause the compiler to cough up an error.
Yes, this principle applies to
enum X { ... };
enum X { ... };
But to me
enum A { X };
enum B { X };
looks more like
struct A { int X; };
struct B { int* X; };
where { introduces a new namespace/scope. If I memorize C++rules
correctly only {} around initializer-list (and of cause enum)
is different. In all other cases { introduces a new namespace/scope
or whatever is the correct english/C++-word for it. I mean within
these {} identifiers that are valid in the enclosing context
can be redeclared and new identifers can be declared.
> namespace Colour
> {
> enum Colour
> {
> Red,
> Green,
> Blue
> };
> };
> using Colour::Colour;
> ...
> Colour TrafficLight = Colour::Red;
This is good! I didn't have the idea of taking the same name for
namespace an enum.
[ header: ]
typedef Color TrafficColor; // Red, Yellow, Green would be better
[ file that uses TrafficColor (and is not interested in Color): ]
TrafficColor Light = Color::Red;
TrafficColor Light = TrafficColor::Red would be more intuitive.
To achieve this you need in the header:
namespace TrafficColor {
typedef Color TrafficColor;
};
using TrafficColor::TrafficColor;
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 13 Jul 1994 10:41:24 GMT Raw View
kevlin@wslint.demon.co.uk (Kevlin Henney) wrote:
> Again I would say that there is less use for enums in C++ than in C, and
> so making them overly important is not useful. When most people use enums
> in C++ it is generally to implement some feature of a class, & hence they
> are already embedded in a useful namespace.
Well, it have been other people that started this discussion. I was playing
a kind of devil's advocate.
Is it possible do use the namespace of a class X where the enum is declared,
so that I can use the enumerators without X:: ?
class TrafficLight {
public:
enum Color { Red, Yellow, Green };
Color state;
};
class Intersection {
TrafficLight light[4];
public: bool invariant ()
{ using TrafficLight; // <== ???
if(light[0].state==Green)
return light[1]!=Green && light[3]!=Green;
if(light[2].state==Green)
return light[1]!=Green && light[3]!=Green;
if(light[1].state==Green)
return light[0]!=Green && light[2]!=Green;
if(light[3].state==Green)
return light[0]!=Green && light[2]!=Green;
return true;
}
};
If one can't I would tend to declare enum Color at global scope
to avoid the unhandy and difficult-to-read:
if(light[0].state==TrafficLight::Green)
return light[1]!=TrafficLight::Green && light[3]!=TrafficLight::Green;
...
(This tention of course may be a personal problem of mine)
> Solutions are only reqd for problems - in the absence of a problem might
> I suggest that no solution is reqd?
> --
> Kevlin A P Henney
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://hphalle2/~schuenem (currently not available from outside)
Devil's advocate
Author: miket@world.std.com (Michael Trachtman)
Date: Sat, 25 Jun 1994 15:36:13 GMT Raw View
James Kanze (kanze@us-es.sel.de) wrote:
: Given that one of the more frequent uses of enum types is to simulate
: enumerated types, and that it is trivial to add the operators if and
: when you so desire (by operator overloading on enum), I think that the
: status quo is the preferred alternative. But I certainly wouldn't
: claim that people who think differently are somehow recommending
: something counter-intuitive.
There are times that I would like to be able to write code that
is both C and C++. C does not provide a way to overload operators.
So, I would like it if C++ allowed you to say flag |= BIT1;
without casting or overloading |=.
Michael T.
Author: jones@cais.cais.com (Ben Jones)
Date: 24 Jun 1994 14:15:32 GMT Raw View
James Kanze (kanze@us-es.sel.de) wrote:
: ...
: Another poster suggested that such operators be legal if at least one
: of the enumerated constants was explicitly given, and illegal
: otherwise. While I like this idea in theory, it introduces two
: "flavors" of enum types, which in turn filter into the type system
: somehow (to change the type of the results of certain operations). So
: it looks like it is more trouble than it is worth, especially as I
: would like to see a standard before the end of the century.
: --
I don't see this as introducing a change which is going to break anyone's
code. The ANSI commitee has already made it illegal to assign an integer
to an enum without an explicit cast:
enum E { a,b,c };
E e1,e2;
...
int i = e1; // legal
e1 = 1; // illegal
e1 = a; // legal
e1 = e2+1; // illegal but unreasonably so
This last statement ought to be handled by promotion. That is, "e2+1"
remains type E, allowing it to be assigned to "e1". If you assign to
an int, that continues to be okay.
I think bit operations should be allowed on enums. That fact that a name
might not have been assigned to a particular bit pattern is not going to
cause any problems since the only limit the compiler might impose on
an enum is the number of bits needed to hold the range of values represented
by the enumerators.
There seem to be a lot of people worried about some kind of "purity of
principle" here. C and C++ have caught precisely on because they allow
you to do anything that is possible to do with a computer. If you want
strong typing taken to ridiculous limits, try Ada.
Ben Jones
jones@arsoftware.arclch.com
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sun, 26 Jun 1994 15:43:31 GMT Raw View
jimad@microsoft.com (Jim Adcock) writes:
>Yet using enums as bitflags to be or'ed together is a common C programming
>practice. If you attempt to deny this
I for one am not suggesting that this usage be disallowed, only that
it should require an explicit conversion.
>you will at best send programmers
>back to using #defines for the bitflags and ints for the bitsets.
I understand why they might go back to using ints for the bitsets,
but why would they want to go back to using #defines for the bitflags?
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 26 Jun 1994 22:17:13 GMT Raw View
In article <9417421.1106@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
>>ekaulaki@kaulakis.win.net (Edward C. Kaulakis) writes:
>>>
>>>What we seem to be talking about is a traditional asm idiom where
>>>x, an enum item, and {x}, a powerset over the enum, have the same
>>>bit encodings, chosen to allow hardware-efficient implementation of
>>
>> Nice analysis. Answer: enums are broke in C++ and
>>the committee has no intention of fixing them. Use classes
>>if you want to have properly enforced contracts.
>
>Hang on. Currently C++ doesn't allow bitwise operators on enums, at
>least unless you overload them yourself. Doesn't that mean that enums
>in C++ are NOT broken?
>
>It's only broken for those people who want to use the old asm idiom,
>and even then only slightly broken, since they can unbreak it themselves
>without much difficulty.
Sorry. Let me clarify: enums are bad language design.
They are beyond retrieval. They are stupid C isms we would
be better without but have to have for C compatibility.
They do not represent a named, sequential, set of named values
(as do Pascal enumerations). The do not provide uniqueness
(as does Eiffel 'unique' feature). They do not put their
values INSIDE the type (as do classes) but pollute their
enclosing space. They do not allow finding the ends of
the represented range, or iteration.
Yes -- at least now they are proper types and
have well defined semantics.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 26 Jun 1994 22:51:51 GMT Raw View
In article <KANZE.94Jun23182314@slsvhdt.us-es.sel.de> kanze@us-es.sel.de (James Kanze) writes:
>In article <rfgCrMGIt.EK9@netcom.com> rfg@netcom.com (Ronald F.
>Guilmette) writes:
>
>|> In article <HARRISON.94Jun18123715@sp10.csrd.uiuc.edu> harrison@sp10.csrd.uiuc.edu (Luddy Harrison) writes:
>|> >Ron Guilmette writes, concerning bitwise operations on enum types:
>
>|> >>> Look, C++ made it invalid to do:
>|> >>> a += b;
>|> >>> where `a' and 'b' are variables of some given enum type.
>|> >>> THIS WAS INTENTIONAL.
>|> >>> Likewise, in C++ you are also not allowed to do:
>|> >>> a &= b;
>|> >>> for similar reasons. So what's wrong with that? I like it. It's called
>|> >>> `type safety'
>
>|> >This is one of those rare instances in which the compiler has enough
>|> >information to do a run-time test to validate the result of the
>|> >operation (namely, that a|b produces a value that is in the enum
>|> >type).
>
>|> Yes, but that would cost cycles. Do I want to pay that price in *my*
>|> deployed code? No way.
>
>No. According to the current working papers, if a and b are of the
>same enum type, then the expression a|b can be safely assigned to that
>enum type.
James, I'm afraid that I'm going to have to ask you to cite chapter and
verse to back up that assertion. Do you mind?
>(Remember, a C++ enum type is *not* an enumerated type in
>the Pascal sense.) So no runtime overhead is necessary.
We seem to be talking at cross-purposes.
Perhaps I should ask Mr. Harrison what he meant by the term `validated'
before I get sucked any further into discussion where we might not even
all agree on the basic terms of reference.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 26 Jun 1994 22:55:37 GMT Raw View
In article <KANZE.94Jun23183011@slsvhdt.us-es.sel.de> kanze@us-es.sel.de (James Kanze) writes:
>In article <rfgCrop6u.KCq@netcom.com> rfg@netcom.com (Ronald F.
>Guilmette) writes:
>|> Take a simple example:
>
>|> enum colors { red = 1, green = 2, orange = 77 };
>
>|> Given that definition, what `type' should the value of
>
>|> (red | green)
>
>|> be said to have?
>
>|> (If you say `enum color' then I'll just have to observe that you and I
>|> disagree about what should and what should not be considered to be a value
>|> of type `enum color'.)
>
>Independantly of what you or I or the original poster have to say
>about what constitutes the type `enum color', the value which results
>from `(red|green)' is a legal value for the type `enum color'
>according to the working papers. According to the working papers,
>given the above definition of `colors', all values in the range 0..127
>inclusive are legal values for `colors', although most of these values
>can only be obtained by casting an int.
All I can say is that I certainly hope that you've gotten the facts wrong
in this case James. If what you are asserting (regarding the working
paper) is in fact true, then I think it diminishes the value of enums
(as independent and distinct types) greatly.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 26 Jun 1994 23:19:15 GMT Raw View
In article <2uc9gt$4m3@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
>John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
>: enums are broke in C++ and
>: the committee has no intention of fixing them. Use classes
>: if you want to have properly enforced contracts.
>
>Why is that?
>
>It seems to me that since they went to all the trouble of making enums create
>separate and distinct types they should finish the job. Why not allow
>enumerator names to overlap:
>
> enum Light { off, on };
> enum Burner { off, low, medium, high };
> enum Speed { slow, medium, fast };
This capability is present in Ada. It could also be provided in C++ fairly
easily. All that would have to be done would be to make a rule that says
that in cases where two or more enumerators having that same name are over-
loaded in the same scope, all references to either of them must be qualified
by the relevant enum type name, as in `Light::off' or `Burner::off'. (But
then of course if you were willing to do all that typing anyway, you might
just as well, use longer... and distinct... names for your enumerators
instead.)
>so that you can say:
>
> Light l1 = off;
> Burner b1 = off;
> Speed s1 = medium;
In Ada, you can do this sort of thing. But C++ tries its best to deny that
it is a language in which the type of a given expression depends in any way
upon context. (Of course we all know that not really true anyway. See ARM
page 326.)
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: dag@control.lth.se (Dag Bruck)
Date: 27 Jun 1994 06:26:47 GMT Raw View
>>>>> "B" == Ben Jones <jones@cais.cais.com> writes:
B> enum E { a,b,c };
B> E e1,e2;
B> e1 = e2+1; // illegal but unreasonably so
B> This last statement ought to be handled by promotion. That is,
B> "e2+1" remains type E, allowing it to be assigned to "e1". If you
B> assign to an int, that continues to be okay.
Consider the following:
extern void f(int);
extern void f(E);
f(e2+1);
As you see, your proposal would change a program that calls f(int) to
a program that calls f(E); I leave it open which one is more correct.
The interesting question, as this newsgroup is mainly concerned with
standardization, is whether your proposal has enough desirable
properties that we should quietly change existing programs. That
question is very hard to answer, but my rather conservative standpoint
is "no." If you really want that behaviour, you can explictly
overload operator+(E, int).
-- Dag
Author: harrison@sp10.csrd.uiuc.edu (Luddy Harrison)
Date: 27 Jun 1994 15:41:27 GMT Raw View
I wrote:
>|> >This is one of those rare instances in which the compiler has enough
>|> >information to do a run-time test to validate the result of the
>|> >operation (namely, that a|b produces a value that is in the enum
>|> >type).
and later Ron Guilmette wrote:
>Perhaps I should ask Mr. Harrison what he meant by the term `validated'
>before I get sucked any further into discussion where we might not even
>all agree on the basic terms of reference.
By "validate" I meant "test whether the value is one of the enumerators".
If the enum is "enum foo { a=10, b=20, c };" and we have the statement
"foo x = g();" where g returns an int, then by validate I mean test
whether the value assigned to x is one of 10, 20, or 21. This is
run-time validation.
When James Kanze writes:
>According to the current working papers, if a and b are of the
>same enum type, then the expression a|b can be safely assigned to that
>enum type.
he is taking enums to be a new kind of integral type that did not
exist in the ARM, as far as I can tell. Here, the enumerators serve
only to determine the size of the enum; they (the enumerators) are not
the only values that can be stored in such an enum. Here,
"validation" can be done at compile-time, but the validation has
almost no relation to the enumerators. If my enum is "enum {
a=MIN_LONG, b=MAX_LONG };" then this "validation" permits any value to
be stored in the enum, even though there are only two enumerators.
That's the crux of the question: does an enum type contain values other
than the enumerators? I thought the ARM permitted an answer of "no",
and I showed an implementation of enums that took advantage of that
fact to save space. I understand that the working paper gives a "yes"
answer. If so, both the implementation I suggested and the stuff about
validation (at run-time) is no longer pertinent.
-Luddy Harrison
Author: ekaulaki@kaulakis.win.net (Edward C. Kaulakis)
Date: Mon, 27 Jun 1994 11:04:09 GMT Raw View
In article <Cs0z8q.K5t@ucc.su.OZ.AU>, John Max Skaller (maxtal@physics.su.OZ.AU) writes:
[snip]
> Sorry. Let me clarify: enums are bad language design.
>They are beyond retrieval. They are stupid C isms we would
>be better without but have to have for C compatibility.
>They do not represent a named, sequential, set of named values
>(as do Pascal enumerations). The do not provide uniqueness
>(as does Eiffel 'unique' feature). They do not put their
>values INSIDE the type (as do classes) but pollute their
>enclosing space. They do not allow finding the ends of
>the represented range, or iteration.
[snip]
No argument *except* that nesting an enum publicly within a class
is the best thing since sliced bread for namespace pollution
control!
class SmarfWarp {
...
public:
enum Status {Dingled, Wermanic, Froidish,};
...
};
class BrimFild {
...
public:
enum Command {Turmeric, Germanic, Wermanic};
...
};
...
foo(SmarfWarp::Wermanic,BrimFild::Wermanic);
!!
The genitive case (Type'attribute) is one of the nice things about
Ada, this sort of simulates it.
While on Ada, niceness, I kind of like wrapping a uint all by
itself in a struct as an X_Handle, and again as a Y_Handle, to
make them incompatible types. Not until the Windows API did I
understand why Ada made new numeric types incompatible by
default...
--
Edward C. Kaulakis (Voice)(805)296-0303
21847 Agajanian Ln., (Fax) (805)296-4718
Santa Clarita CA 91350 ekaulaki@kaulakis.win.net
I *sell* my opinions. But for you, a special price! $0.02!
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Mon, 27 Jun 1994 21:31:48 GMT Raw View
In article <rfgCs110q.F8v@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <KANZE.94Jun23183011@slsvhdt.us-es.sel.de> kanze@us-es.sel.de (James Kanze) writes:
enum colors {red, blue =77};
>>according to the working papers. According to the working papers,
>>given the above definition of `colors', all values in the range 0..127
>>inclusive are legal values for `colors', although most of these values
>>can only be obtained by casting an int.
>
>All I can say is that I certainly hope that you've gotten the facts wrong
>in this case James.
James is right. Its the smallest bitfield (in effect).
>If what you are asserting (regarding the working
>paper) is in fact true, then I think it diminishes the value of enums
>(as independent and distinct types) greatly.
What alternative is there? Enums are already badly
"diminished" in their semantics -- they're too much of
a hack to bother with. Nothing is lost by the ANSI/ISO committee's
current definition -- but type safety is gained and the range
of values is now well defined. No other definition seems to
provide all the facilities of the C enum, that is, cope
with most of the common idioms.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Mon, 27 Jun 1994 21:39:00 GMT Raw View
In article <rfgCs1244.HE9@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <2uc9gt$4m3@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
>>John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
>>: enums are broke in C++ and
>>: the committee has no intention of fixing them. Use classes
>>: if you want to have properly enforced contracts.
>>
>>Why is that?
>>
>>It seems to me that since they went to all the trouble of making enums create
>>separate and distinct types they should finish the job. Why not allow
>>enumerator names to overlap:
>>
>> enum Light { off, on };
>> enum Burner { off, low, medium, high };
>> enum Speed { slow, medium, fast };
I would like this. The correct way to handle it is to
require one to write:
Light::off
and disallow just
off
>
>This capability is present in Ada. It could also be provided in C++ fairly
>easily. All that would have to be done would be to make a rule that says
>that in cases where two or more enumerators having that same name are over-
>loaded in the same scope, all references to either of them must be qualified
>by the relevant enum type name, as in `Light::off' or `Burner::off'.
That would work too -- and preserved C compatibility.
>(But
>then of course if you were willing to do all that typing anyway, you might
>just as well, use longer... and distinct... names for your enumerators
>instead.)
>
>>so that you can say:
>>
>> Light l1 = off;
>> Burner b1 = off;
>> Speed s1 = medium;
>
>In Ada, you can do this sort of thing.
>But C++ tries its best to deny that
>it is a language in which the type of a given expression depends in any way
>upon context. (Of course we all know that not really true anyway. See ARM
>page 326.)
Yes, but why add to the confusion with even more cases of this?
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Fri, 1 Jul 1994 19:02:29 GMT Raw View
In article <2uc9gt$4m3@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
>John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
>: enums are broke in C++ and
>: the committee has no intention of fixing them. Use classes
>: if you want to have properly enforced contracts.
>
>Why is that?
Because enums serve too many masters.
>
>It seems to me that since they went to all the trouble of making enums create
>separate and distinct types they should finish the job.
That sounds reasonable to me but the indications are that
many people want a Standard NOW if not yesterday and will not
wish to wait longer for this improvement to be discussed.
>Why not allow
>enumerator names to overlap:
Why spend time discussing it when there are other priorities?
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 4 Jul 1994 07:47:11 GMT Raw View
In article <2umnpn$hs2@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
>Ronald F. Guilmette (rfg@netcom.com) wrote:
>: >so that you can say:
>: >
>: > Light l1 = off;
>: > Burner b1 = off;
>: > Speed s1 = medium;
>
>: In Ada, you can do this sort of thing. But C++ tries its best to deny that
>: it is a language in which the type of a given expression depends in any way
>: upon context. (Of course we all know that not really true anyway. See ARM
>: page 326.)
>
>If C++ can handle expressions like "x.a" and "y.a" where "x" and "y" are
>completely different classes that happen to have a member called "a", why
>couldn't it handle "x=a" and "y=a" where "x" and "y" are completely different
>enumerated types that happen to have an enumerator "a"?
Hey! Don't ask me. I just work here.
But seriously, it would be nice to have answers to this and many other
such questions of a similar form, but I believe that we are all going
to have to learn to live without such answers.
The last I heard was that the C++ standardization committee has decided
NOT to produce any document resembling a ``rationale''.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 6 Jul 1994 10:45:14 GMT Raw View
I think one reason for problems with enumerator names is an
unorthogonality (a non-analogy) regarding namespace-scoping:
typedef t0 a;
struct N1 { typedef t1 a; };
union N2 { typedef t2 a; };
namespace N3 { typedef t3 a; };
void N4() { typedef t4 a; };
are fine. Every time the "{" introduces a new namespace.
The new declarations can be accessed using the scope-operator:
::a, N1::a, N2::a, N3::a (an unothogonality: N4::a can't be accessed).
enum N5 { a };
places the identifier 'a' directly into the namespace of N5.
For the sake of orthogonality the {} of enum should introduce a new
namespace like the {} of struct, class, union, namespace and function
does. E1::a and E2::a would be used to access the enumerators....
- But this would be unhandy and break nearly all code using enum.
Proposal:
1. "enum X { x };" introduces a new namespace X.
By the current rules for namespaces this implies:
a. "enum X1 { x }; enum X2 { x };" is allowed
b. Qualified access is possible: X1::x, X2::x
c. "using X1::x;" is possible (? - I'm not realy sure)
2. This namespace is automatically opened, so that x
can be used without X::
3. If x is ambiguos this is only flagged at the point of
enumerator-usage.
Regarding implementation:
ad 1. The introduction of a new namespace is an automatisation
of the currently possible workaround of wrapping every
enum-declaration into a namespace.
ad 2. After the {} the same actions as if there where a "using X;"
have to be taken.
ad 3. Namelookup of enumerators is the same as for any member of
any (other kind of) namespace that is used by "using X;"
(not: "using namespace X;")
Advantages:
- Namespacing for enum is more orthogonal to struct,class,union,function.
- Ambiguities of enumeratornames are not flagged at the point of enum-
declaration but at the point of enumerator-usage. E.g. You can include
different headers with declarations of enumerator x without problems.
- Only when you want to use ambigous enumeratornames you have to
qualify which one you want (X1::x).
- If you prefere one of the ambigous enumeratornames x you can write
"using X1::x;" than you can access it by "x" whereas you
have to write "X2::x" to access the other.
N.B. (1.) is equivalent to the first part of Ben Jones' proposal.
Contextsenitiv "X1 a = x; X2 b = x;" is still not possible and
IMHO whould be a too big and not necessary-enough extension of C++.
What do you think? Is this a reasonable compromise?
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
WWW: http://hphalle2/~schuenem (currently not available from outside)
Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 28 Jun 1994 03:21:30 GMT Raw View
>>>>> Ronald F Guilmette <rfg@netcom.com> writes:
> In Ada, you can do this sort of thing. But C++ tries its best to deny that
> it is a language in which the type of a given expression depends in any way
> upon context. (Of course we all know that not really true anyway. See ARM
> page 326.)
I see ARM page 326, but I don't see your point. In all of the examples
there, each subexpression has a type independent of the enclosing
expression; only when those subexpressions are then used do they need to be
converted to other types.
In any case, I think that the issue is not so much the type of a given
expression, but the meaning of a particular name, which is definitely
independent of context. Well, almost; a name preceded by 'class' or one of
its ilk or followed by '::' or '<' may have a different meaning from the
one it would have considered independently. But these are syntactic, not
semantic, considerations; determining the meaning of a name based on the
enclosing expression is a major, and undesirable, step up in obscurity.
Jason
Author: jones@cais.cais.com (Ben Jones)
Date: 27 Jun 1994 14:30:15 GMT Raw View
Ronald F. Guilmette (rfg@netcom.com) wrote:
: In article <2uc9gt$4m3@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
: >John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: >It seems to me that since they went to all the trouble of making enums create
: >separate and distinct types they should finish the job. Why not allow
: >enumerator names to overlap:
: >
: > enum Light { off, on };
: > enum Burner { off, low, medium, high };
: > enum Speed { slow, medium, fast };
: This capability is present in Ada. It could also be provided in C++ fairly
: easily. All that would have to be done would be to make a rule that says
: that in cases where two or more enumerators having that same name are over-
: loaded in the same scope, all references to either of them must be qualified
: by the relevant enum type name, as in `Light::off' or `Burner::off'. (But
: then of course if you were willing to do all that typing anyway, you might
: just as well, use longer... and distinct... names for your enumerators
: instead.)
: >so that you can say:
: >
: > Light l1 = off;
: > Burner b1 = off;
: > Speed s1 = medium;
: In Ada, you can do this sort of thing. But C++ tries its best to deny that
: it is a language in which the type of a given expression depends in any way
: upon context. (Of course we all know that not really true anyway. See ARM
: page 326.)
If C++ can handle expressions like "x.a" and "y.a" where "x" and "y" are
completely different classes that happen to have a member called "a", why
couldn't it handle "x=a" and "y=a" where "x" and "y" are completely different
enumerated types that happen to have an enumerator "a"?
Ben Jones
Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/164 71425)
Date: 28 Jun 1994 19:08:35 GMT Raw View
In article <HARRISON.94Jun27104127@sp10.csrd.uiuc.edu>
harrison@sp10.csrd.uiuc.edu (Luddy Harrison) writes:
|> When James Kanze writes:
|> >According to the current working papers, if a and b are of the
|> >same enum type, then the expression a|b can be safely assigned to that
|> >enum type.
|> he is taking enums to be a new kind of integral type that did not
|> exist in the ARM, as far as I can tell. Here, the enumerators serve
|> only to determine the size of the enum; they (the enumerators) are not
|> the only values that can be stored in such an enum. Here,
|> "validation" can be done at compile-time, but the validation has
|> almost no relation to the enumerators. If my enum is "enum {
|> a=MIN_LONG, b=MAX_LONG };" then this "validation" permits any value to
|> be stored in the enum, even though there are only two enumerators.
|> That's the crux of the question: does an enum type contain values other
|> than the enumerators? I thought the ARM permitted an answer of "no",
|> and I showed an implementation of enums that took advantage of that
|> fact to save space. I understand that the working paper gives a "yes"
|> answer. If so, both the implementation I suggested and the stuff about
|> validation (at run-time) is no longer pertinent.
All of my books are currently in boxes, as I am in the process of
moving, but if memory serves me right, Luddy Harrison is correct with
regards to the ARM. There was a specific proposal which explicitly
changed this; again, if memory serves me right, it was passed in
Portland. Basically, Luddy Harrison's interpretation of my text is
correct; the proposal is written in much more difficult to understand
standardese, but it basically comes out to the enumerators serving
only to determine the (minimum) size of an enum.
It does occur to me that my words are not too precise. To assign a|b
to the enum would still require a cast. But it is guaranteed that the
value can be assigned without undefined behavior. And that the value
can be reread, e.g.: the following is a conforming program (using the
sense of conforming from the C standard):
enum X { a , b , c } ;
void
f()
{
X x = (X)( a | b ) ;
if ( x == 3 ) // This *must* evaluate true
{
// ...
}
}
The above program exibits *no* undefined behavior UNDER THE PROPOSAL
ADAPTED IN PORTLAND.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Wed, 29 Jun 1994 02:35:22 GMT Raw View
In article <2umnpn$hs2@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
>
>If C++ can handle expressions like "x.a" and "y.a" where "x" and "y" are
>completely different classes that happen to have a member called "a", why
>couldn't it handle "x=a" and "y=a" where "x" and "y" are completely different
>enumerated types that happen to have an enumerator "a"?
Because x.a involves lookup of a in the class of x.
Assignment does not imply lookup.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 29 Jun 1994 05:23:51 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>jones@cais.cais.com (Ben Jones) writes:
>>
>>If C++ can handle expressions like "x.a" and "y.a" where "x" and "y" are
>>completely different classes that happen to have a member called "a", why
>>couldn't it handle "x=a" and "y=a" where "x" and "y" are completely different
>>enumerated types that happen to have an enumerator "a"?
>
> Because x.a involves lookup of a in the class of x.
>Assignment does not imply lookup.
Well, why not? Why shouldn't it?
In fact, you're wrong anyway - assignment does imply lookup.
Consider the following:
struct X {
static void foo(int);
static void foo(char *);
static void baz() {
void (*p) (int) = &X::foo;
}
};
Well, maybe you want to call that ambiguity resolution, not lookup, but
still the point remains - if we can overload functions, then why not
overload enums?
[As with many of my posts to this forum, I'm not necessarily supporting the
idea, just playing Devil's advocate.]
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: jones@cais.cais.com (Ben Jones)
Date: 29 Jun 1994 13:17:05 GMT Raw View
John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: In article <2umnpn$hs2@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
: >
: >If C++ can handle expressions like "x.a" and "y.a" where "x" and "y" are
: >completely different classes that happen to have a member called "a", why
: >couldn't it handle "x=a" and "y=a" where "x" and "y" are completely different
: >enumerated types that happen to have an enumerator "a"?
: Because x.a involves lookup of a in the class of x.
: Assignment does not imply lookup.
Yes, but assignment usually implies type conversion which implies that the
compiler knows something about both operands of "=".
Look, it's really quite simple:
When a named enumeration is defined, its enumerators are defined in a
private scope rather than in the scope in which the enumeration is
declared. This prevents conflicts with other enumerations declared in
that same scope:
enum E { a,b,c };
enum F { c,b,a };
The following rules are used to evaluate a name:
1. If the left-handed argument of a binary operator is of an
enumerated type, the right handed argument will be evaluated first in
the context of that type.
E e1 = a;
F f1 = a;
2. If the argument to "switch" is of an enumerated type, the "case"
labels will be evaluated first in the context of that type.
switch (e1) { case a: ... case b: ... case c: ... }
switch (f1) { case c: ... case b: ... case a: ... }
3. If the dummy argument of a function is of an enumerated type, a
name passed as an actual argument will be evaluated first in the
context of that type. Each test for an overload of the function
will evaluate the name:
void ee(E);
void ff(F);
...
ee(a);
ff(a);
4. It is not necessary for the "enum" to be defined in the current
scope for all this to work:
class X
{
enum XE { i,j,k };
XE m;
void f(XE);
};
...
X x1;
x1.m = i;
switch (x1.m) { case i: ... case j: ... case k: ... }
x1.f(j);
5. If a name is assigned to an integer and more than one enumeration
defines that name, an ambiguity is flagged. The scope resolution
operator "::" may be used to resolve the ambiguity:
int t = F::a;
6. If an integer value occurs in a binary expression with an
enumerated type, it should be promoted to that enumerated type:
E e1 = a;
e1 = e1+1; // Resulting in e1 == b
e1++; // Resulting in e1 == c
NOTE: There has been a recent trend away from allowing integers to be
promoted to enumerated types in recent C++ compilers. The above
rule reverses the current practice which "promotes" enumerated types
to integers. Enumerated types would be converted to integers if
assigned to integers. Assignment of integers to enumerated types
is disallowed unless a cast is performed.
This scheme is implemented in ARC++, an extension of C++, which piggybacks
onto C++ compilers to provide this and other language extensions. If you
would like to give it a try, go to the anonymous FTP:
arsoftware.arclch.com: /pub/arsoftware/arc++
and get "arc.READ_ME" for downloading instructions.
Ben Jones
jones@arsoftware.arclch.com
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Thu, 30 Jun 1994 07:40:01 +0000 Raw View
In article <2uovfv$muo@sun.cais.com> jones@cais.cais.com "Ben Jones" writes:
>John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
>: In article <rfgCs1244.HE9@netcom.com> rfg@netcom.com (Ronald F. Guilmette)
> writes:
>: >In article <2uc9gt$4m3@sun.cais.com> jones@cais.cais.com (Ben Jones) writes:
>: >>It seems to me that since they went to all the trouble of making enums
> create
>: >>separate and distinct types they should finish the job. Why not allow
>: >>enumerator names to overlap:
>: >>
>: >> enum Light { off, on };
>: >> enum Burner { off, low, medium, high };
>: >> enum Speed { slow, medium, fast };
>
>: I would like this. The correct way to handle it is to
>: require one to write:
>
>: Light::off
>
>: and disallow just
>
>: off
>
>Isn't that sort of like making someone say in English: "Turn the light to
>the 'off' which pertains to a Light"?
>
>The reason I suggest overloading enums and having context-sensitive
>expressions is that the lack of such capability leads programmers to
>use two ugly alternatives:
>
>1) They make ugly names for keywords like "O_RDWR" or "Wm_Create" so that
>names don't conflict. Forcing a qualifier on an enum would amount to the
>same thing.
>
>2) They create manipulators:
>
> void dec(iostream&);
> void hex(iostream&);
> iostream& operator << (iostream&,void (*)(iostream&));
>
>so that you can say things like:
>
> cout << hex << 100 << dec;
>
>by virtue of "hex" and "dec" getting executed as side effects by
>operator <<.
>
>
>If you could say:
>
> enum ioflag { dec,hex,...};
> iostream& operator << (iostream&,ioflag);
>
>and be able to say:
>
> cout << hex << 100 << dec;
>
>instead of:
>
> cout << ioflag::hex << 100 << iflag::dec;
>
>the programming would be so much more straight-forward.
>There would be less confusion rather than more.
There is already a solution to all this: namespace. It is doubtful that
another mechanism is reqd.
--
Kevlin Henney
repeat 3 echo there\'s no place like ~
Author: miket@world.std.com (Michael Trachtman)
Date: Thu, 30 Jun 1994 12:20:58 GMT Raw View
Kevlin Henney (kevlin@wslint.demon.co.uk) wrote:
: There is already a solution to all this: namespace. It is doubtful that
: another mechanism is reqd.
Namespaces don't help.
For if you have:
namespace E1a
{
enum E1 { A = 25, B, C};
};
namespace E2a
{
enum E2 { A = 7, B , C};
};
using E1a;
using E2a;
void
main ()
{
E1 e1;
E2 e2;
e1 = a; // Should be OK (but isn't under current rules). e1 == 25
e2 = a; // Should be OK (but isn't under current rules). e2 == 7
e2 = e1; // Should not be OK.
e2 = static_cast<E2>(e1); // Should be OK.
e1 = static_cast<E1>(e2); // May not be OK, E1 may not have enough bits.
}
What did namespaces give you ??
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Fri, 1 Jul 1994 13:17:46 +0000 Raw View
In article <Cs7MAy.Jn4@world.std.com>
miket@world.std.com "Michael Trachtman" writes:
>Kevlin Henney (kevlin@wslint.demon.co.uk) wrote:
>
>: There is already a solution to all this: namespace. It is doubtful that
>: another mechanism is reqd.
>
>Namespaces don't help.
>
>For if you have:
>
>namespace E1a
>{
> enum E1 { A = 25, B, C};
>};
>
>namespace E2a
>{
> enum E2 { A = 7, B , C};
>};
>
>using E1a;
>using E2a;
>
>void
>main ()
>{
> E1 e1;
> E2 e2;
>
> e1 = a; // Should be OK (but isn't under current rules). e1 == 25
> e2 = a; // Should be OK (but isn't under current rules). e2 == 7
>
> e2 = e1; // Should not be OK.
> e2 = static_cast<E2>(e1); // Should be OK.
> e1 = static_cast<E1>(e2); // May not be OK, E1 may not have enough bits.
>}
>
>What did namespaces give you ??
Quite a lot, if you understand what they're for and how they work. The
solution to your problem is either
/1/ don't use 'using' for both namespaces & explicitly
qualify uses of the one not 'used'
/2/ leave as is, and qualify the clashes that the compiler
cheerfully throws back at you
I would seriously doubt your use of the term 'Should be OK'. IMHO, it
shouldn't be and, as it happens, isn't. If you intentionally attempt
to clash namespaces that is your problem and not the language's.
--
Kevlin Henney
repeat 3 echo there\'s no place like ~
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Fri, 1 Jul 1994 18:50:44 GMT Raw View
In article <9418015.12495@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
>>jones@cais.cais.com (Ben Jones) writes:
>>>
>>>If C++ can handle expressions like "x.a" and "y.a" where "x" and "y" are
>>>completely different classes that happen to have a member called "a", why
>>>couldn't it handle "x=a" and "y=a" where "x" and "y" are completely different
>>>enumerated types that happen to have an enumerator "a"?
>>
>> Because x.a involves lookup of a in the class of x.
>>Assignment does not imply lookup.
>
>Well, why not? Why shouldn't it?
>
>In fact, you're wrong anyway - assignment does imply lookup.
x.a involves lookup of the name 'a'. 'a' is not
an argument to a function. It may BE a function.
x = a is different, it is the assignment operator
that is looked up in the class of x, and overload resolution
performed using the type of a. Its not 'a' that is looked up.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: miket@world.std.com (Michael Trachtman)
Date: Thu, 7 Jul 1994 02:10:43 GMT Raw View
The problem that we still have is that 'C' allows.
typedef enum { BIT0 = 0x0001, BIT1 = 0x0002, BIT2 = 0x0004 } BITS;
BITS a;
a = BIT0 | BIT2;
a = a | BIT0;
a |= BIT1;
while C++ does not.
This probably breaks a fair quantity of 'C' code when compiled as C++.
Michael Trachtman.
Author: dag@control.lth.se (Dag Bruck)
Date: 07 Jul 1994 06:36:24 GMT Raw View
>>>>> "MT" == Michael Trachtman <miket@world.std.com> writes:
MT> The problem that we still have is that 'C' allows.
MT> (Example or or'ing enumerators deleted.)
MT> while C++ does not.
MT> This probably breaks a fair quantity of 'C' code when compiled as
MT> C++.
Luckily the standardization committee has decided that you will be
able to overload on enumerations. This makes the following possible:
BITS operator | (BITS x, BITS y)
{ return /* some expression here */; }
By adding this operator you can compile your old C code with a C++
compiler, and without risking any type mis-matches.
-- Dag Bruck
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Thu, 7 Jul 1994 12:39:19 +0000 Raw View
In article <2ve1vq$70v@hpsystem1.informatik.tu-muenchen.de>
schuenem@Informatik.TU-Muenchen.DE "Ulf Schuenemann" writes:
>I think one reason for problems with enumerator names is an
>unorthogonality (a non-analogy) regarding namespace-scoping:
>
> typedef t0 a;
> struct N1 { typedef t1 a; };
> union N2 { typedef t2 a; };
> namespace N3 { typedef t3 a; };
> void N4() { typedef t4 a; };
>
>are fine. Every time the "{" introduces a new namespace.
>The new declarations can be accessed using the scope-operator:
>::a, N1::a, N2::a, N3::a (an unothogonality: N4::a can't be accessed).
>
> enum N5 { a };
>
>places the identifier 'a' directly into the namespace of N5.
>
>For the sake of orthogonality the {} of enum should introduce a new
>namespace like the {} of struct, class, union, namespace and function
>does. E1::a and E2::a would be used to access the enumerators....
>- But this would be unhandy and break nearly all code using enum.
[proposal deleted]
I think you almost answered your own question w/ the unorthogonality issue:
{...} does not always introduce a namespace. {...}, like static, is used
to mean many - possibly too many - things. There is no problem w/ enums
as they currently stand. In C++ enums are typically used w/i classes to
represent some aspect of that class, rather than roaming freely in wild
badlands of the global namespace. I'm not sure that another level of
namespace nesting would help things, but if you want it you don't have
to change the language:
namespace Colour
{
enum Type
{
Red,
Green,
Blue
};
};
--
Kevlin Henney
repeat 3 echo there\'s no place like ~
Author: jones@cais.cais.com (Ben Jones)
Date: 7 Jul 1994 14:25:44 GMT Raw View
Ulf Schuenemann (schuenem@Informatik.TU-Muenchen.DE) wrote:
:
: Proposal:
: 1. "enum X { x };" introduces a new namespace X.
: By the current rules for namespaces this implies:
: a. "enum X1 { x }; enum X2 { x };" is allowed
: b. Qualified access is possible: X1::x, X2::x
: c. "using X1::x;" is possible (? - I'm not realy sure)
: 2. This namespace is automatically opened, so that x
: can be used without X::
: 3. If x is ambiguos this is only flagged at the point of
: enumerator-usage.
:
: ...
:
: N.B. (1.) is equivalent to the first part of Ben Jones' proposal.
: Contextsenitiv "X1 a = x; X2 b = x;" is still not possible and
: IMHO whould be a too big and not necessary-enough extension of C++.
: What do you think? Is this a reasonable compromise?
This would be a reasonable start, at least. One of the problems with the
way enums are implemented right now is that if you #include two different
headers which happen to define the same enumerator in the current scope,
the headers will conflict and there is nothing you can do about it.
However, I think it would be better to implement context sensitivity.
Without it, you will still have to qualify names which overlap and that
will probably confuse and annoy people. It was really not that difficult to
implement in ARC++. The rules I suggested really boiled down to a single
point in the compiler where type promotion is performed:
* If one expression is of an enumerated type and the other expression
has a name token, look up that name first in the scope of the enumerated
type.
At the very least, this would get rid of almost all name conflicts with
enumerated types and make it possible finally to have reasonable naming
conventions for keywords.
* * * *
Then if you want to go one step further and allow arithmetic operations
on enumerated types, the rules would be:
* If one expression is of an enumerated type and the other expression
is numeric, cast the numeric expression to the enumerated type.
* An enumerated type may be assigned to a numeric type.
* A numeric type may NOT be assigned to an enumerated type without
a cast.
These rules would not break any existing C++ code under the current
standard except for one single case: passing an expression involving
an enumerated type and an int to an overloaded function or operator
where one version wants an int and another wants that enumerated type.
Ben Jones
jones@arsoftware.arclch.com
Author: h.b.furuseth@usit.uio.no (Hallvard B Furuseth)
Date: 8 Jul 1994 08:31:21 GMT Raw View
In article <DAG.94Jul7083625@bellman.control.lth.se> dag@control.lth.se (Dag Bruck) writes:
> Luckily the standardization committee has decided that you will be
> able to overload on enumerations. This makes the following possible:
>
> BITS operator | (BITS x, BITS y)
> { return /* some expression here */; }
>
> By adding this operator you can compile your old C code with a C++
> compiler, and without risking any type mis-matches.
enum BITS { ... };
inline BITS operator | (BITS x, BITS y) { return (BITS)((int)x | (int)y); }
inline BITS operator & (BITS x, BITS y) { return (BITS)((int)x & (int)y); }
inline BITS operator ~ (BITS x) { return (BITS)~(int)x; }
Great. The full declaration of BITS is now 4 times larger than the
one-liner which was enough before.
Yet another place where C++ forces you to code an operation by hand
which the compiler already can do.
--
Hallvard
Author: dag@control.lth.se (Dag Bruck)
Date: 08 Jul 1994 11:07:41 GMT Raw View
>>>>> "H" == Hallvard B Furuseth <h.b.furuseth@usit.uio.no> writes:
H> Great. The full declaration of BITS is now 4 times larger than the
H> one-liner which was enough before.
H> Yet another place where C++ forces you to code an operation by hand
H> which the compiler already can do.
Assuming that the compiler knows best...
If you just want to do bit operations without any added effort, why
not use integers? Integers are there and you don't have to code
anything.
-- Dag
Author: h.b.furuseth@usit.uio.no (Hallvard B Furuseth)
Date: 8 Jul 1994 16:49:15 GMT Raw View
In article <DAG.94Jul8130741@bellman.control.lth.se> dag@control.lth.se (Dag Bruck) writes:
> If you just want to do bit operations without any added effort, why
> not use integers? Integers are there and you don't have to code
> anything.
I could say exactly the same about what you use enums for.
I use them because
They give some type checking.
My debugger knows about enums and shows a value's name when possible.
I use C libraries with C++.
I do not intend to modify correctly working libraries (maybe in C)
whenever I do stumble over an assignment to an enum which "should have
been int" in this new C++, and I expect many others won't either. It is
much quicker and simpler to cast the value to enum, thus abandoning any
type safety. So I think this is one place where too tight type checking
in practice will reduce type safety as well as add to it.
--
Hallvard
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Thu, 23 Jun 1994 11:25:47 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>ekaulaki@kaulakis.win.net (Edward C. Kaulakis) writes:
>>
>>What we seem to be talking about is a traditional asm idiom where
>>x, an enum item, and {x}, a powerset over the enum, have the same
>>bit encodings, chosen to allow hardware-efficient implementation of
>
> Nice analysis. Answer: enums are broke in C++ and
>the committee has no intention of fixing them. Use classes
>if you want to have properly enforced contracts.
Hang on. Currently C++ doesn't allow bitwise operators on enums, at
least unless you overload them yourself. Doesn't that mean that enums
in C++ are NOT broken?
It's only broken for those people who want to use the old asm idiom,
and even then only slightly broken, since they can unbreak it themselves
without much difficulty.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: kanze@us-es.sel.de (James Kanze)
Date: 23 Jun 1994 16:44:42 GMT Raw View
In article <28063@alice.att.com> bs@alice.att.com (Bjarne Stroustrup)
writes:
|> jason@cygnus.com (Jason Merrill @ Cygnus Support, Mountain View, CA) writes
|> > >>>>> David Sachs <b91926@fsgi01.fnal.gov> writes:
|> > > If you wish to handle operations on an enum type, you probably
|> > > should provide overloaded operator functions to do so. This is
|> > > a post-ARM addition to C++.
|> > This is also unnecessary overhead; if I have two enums ONE and TWO with
|> > values of 1 and 2, I want to be able to use the built-in | operator to
|> > combine them into THREE.
|> Hmm. Are you sure that is always a good idea?
|> Consider:
|> enum N { ONE=1, TWO, THREE, FOUR };
|> The value of ONE|TWO is 3 which just happenss to be the value of THREE.
|> However, TWO|THREE doesn't have the same value as FOUR. In fact, TWO|THREE
|> doesn't have a value that is representable as an N.
|> Exactly how to generalize the usual arithmetical and logical operations to
|> apply to enumerations is not obvious.
If enum's were just enumerated types, I don't think that there could
be any real argument against what you are saying. It just doesn't
make sense to `or' two enumerated types.
But in C++, enum's are something more than enumerated types (although
enumerated types remains an important use). In this context, I'm not
sure that it wouldn't be better defining `|', `&', `^' and the
corresponding assignment op's for enum's. If the two operands are of
the same enum type, the results can always be stored in this type
without error (according to the working papers).
The major problem I see in this is what to do about `~'. On one hand,
you want `~', since it is used in the traditional idiom for resetting
bits. On the other hand, `~ONE', above, may not fit in an `N'. While
I don't think that the problem is unsurmountable, it does require more
effort than just saying that the operator is allowed.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: jimad@microsoft.com (Jim Adcock)
Date: Wed, 22 Jun 1994 17:27:49 GMT Raw View
In article <28063@alice.att.com> bs@alice.att.com (Bjarne Stroustrup) writes:
|jason@cygnus.com (Jason Merrill @ Cygnus Support, Mountain View, CA) writes
|
| > >>>>> David Sachs <b91926@fsgi01.fnal.gov> writes:
| >
| > > If you wish to handle operations on an enum type, you probably
| > > should provide overloaded operator functions to do so. This is
| > > a post-ARM addition to C++.
| >
| > This is also unnecessary overhead; if I have two enums ONE and TWO with
| > values of 1 and 2, I want to be able to use the built-in | operator to
| > combine them into THREE.
|
|Hmm. Are you sure that is always a good idea?
|
|Consider:
|
| enum N { ONE=1, TWO, THREE, FOUR };
|
|The value of ONE|TWO is 3 which just happenss to be the value of THREE.
|However, TWO|THREE doesn't have the same value as FOUR. In fact, TWO|THREE
|doesn't have a value that is representable as an N.
|
|Exactly how to generalize the usual arithmetical and logical operations to
|apply to enumerations is not obvious.
Yet using enums as bitflags to be or'ed together is a common C programming
practice. If you attempt to deny this you will at best send programmers
back to using #defines for the bitflags and ints for the bitsets. Would
that programmers were willing to use 'real' bitfields, but history has
demonstrated that they will not do so. I suspect the commonly horrible
implementation of bitfields on most C/C++ compilers is only part of the
problem.
Author: jimad@microsoft.com (Jim Adcock)
Date: Wed, 22 Jun 1994 17:42:38 GMT Raw View
In article <9417100.13714@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
|enum. What's wrong with using
|
| enum { BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004 };
|
|or
|
| const int BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004;
|
|and then just using
|
| int flags = BIT1;
| flags |= BIT2;
| flags &= BIT3;
int cnt = 123;
...
Func(cnt, flags); // fine, typesafe, compiler accepts
Func(flags, cnt); // fine, typesafe, compiler accepts
The basic problem is that 'ints' AREN'T in common C/C++ usage, but
rather have become an excuse to embed untypechecked assembly language
in one's coding wherever one wants. While using enums as bitsets may
feel impure, but at least the enums form a unique type that *some* amount
of typechecking can be performed on.
Author: kanze@us-es.sel.de (James Kanze)
Date: 23 Jun 1994 17:23:14 GMT Raw View
In article <rfgCrMGIt.EK9@netcom.com> rfg@netcom.com (Ronald F.
Guilmette) writes:
|> In article <HARRISON.94Jun18123715@sp10.csrd.uiuc.edu> harrison@sp10.csrd.uiuc.edu (Luddy Harrison) writes:
|> >Ron Guilmette writes, concerning bitwise operations on enum types:
|> >>> Look, C++ made it invalid to do:
|> >>> a += b;
|> >>> where `a' and 'b' are variables of some given enum type.
|> >>> THIS WAS INTENTIONAL.
|> >>> Likewise, in C++ you are also not allowed to do:
|> >>> a &= b;
|> >>> for similar reasons. So what's wrong with that? I like it. It's called
|> >>> `type safety'
|> >This is one of those rare instances in which the compiler has enough
|> >information to do a run-time test to validate the result of the
|> >operation (namely, that a|b produces a value that is in the enum
|> >type).
|> Yes, but that would cost cycles. Do I want to pay that price in *my*
|> deployed code? No way.
No. According to the current working papers, if a and b are of the
same enum type, then the expression a|b can be safely assigned to that
enum type. (Remember, a C++ enum type is *not* an enumerated type in
the Pascal sense.) So no runtime overhead is necessary.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: kanze@us-es.sel.de (James Kanze)
Date: 23 Jun 1994 17:30:11 GMT Raw View
In article <rfgCrop6u.KCq@netcom.com> rfg@netcom.com (Ronald F.
Guilmette) writes:
|> In article <CrnEJH.7Ju@world.std.com> miket@world.std.com (Michael Trachtman) writes:
|> >I think that when the enum are being used as bitfields, it is clear that
|> > e1 |= e2 as well as e1 &= e2 are perfectly "type safe".
|> >
|> >The inputs and the outputs are of the same type...
|> I'm sorry, but neither of your assertions (quoted here) are the least bit
|> clear... at least not to me.
|> Take a simple example:
|> enum colors { red = 1, green = 2, orange = 77 };
|> Given that definition, what `type' should the value of
|> (red | green)
|> be said to have?
|> (If you say `enum color' then I'll just have to observe that you and I
|> disagree about what should and what should not be considered to be a value
|> of type `enum color'.)
Independantly of what you or I or the original poster have to say
about what constitutes the type `enum color', the value which results
from `(red|green)' is a legal value for the type `enum color'
according to the working papers. According to the working papers,
given the above definition of `colors', all values in the range 0..127
inclusive are legal values for `colors', although most of these values
can only be obtained by casting an int.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: kanze@us-es.sel.de (James Kanze)
Date: 23 Jun 1994 17:34:53 GMT Raw View
In article <9417017.28671@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU
(Fergus Henderson) writes:
|> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
|> >In article <2ttu1i$j8p@crl2.crl.com> itz@crl.com (Ian T. Zimmerman) writes:
|> >>enum AtMostTwo { eZero, eOne, eTwo };
|> >>AtMostTwo Fudge (void) { return (eOne | eTwo); }
|> >>...
|> >>IMHO, this is just a coding manifestation of a problem on a more abstract
|> >>semantic (aesthetic?) level. The bitwise operations simply do not
|> >>correspond to any well-defined algebraic operators on the _type_
|> >>AtMostTwo. Or, to turn it around, if you want them, you forfeit the right
|> >>to consider enums as first-class types.
|> > Wrong. The result of eOne | eTwo is
|> > AtMostTwo(3)
|> Yes, but this is so unintuitive that you should need to use a cast.
This is only unintuitive if you consider enum's to be enumerated
types. In the current working papers, in any case, this is not the
case. While a C++ enum can be used to simulate an enumerated type, it
is not really an enumerated type in the strict sense of the word.
When enum's are used as enumerated types, the above is unintuitive.
But in other cases, when for example, enum's are used to specify bit
masks, such results are perfectly valid, and quite intuitive.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: h.b.furuseth@usit.uio.no (Hallvard B Furuseth)
Date: 23 Jun 1994 17:30:33 GMT Raw View
In article <Crt76M.1wy@microsoft.com> jimad@microsoft.com (Jim Adcock) writes:
> Would
> that programmers were willing to use 'real' bitfields, but history has
> demonstrated that they will not do so.
Becuase ORed flags can be manipulated much easier than bitfields. Would
you have preferred the flags to open() to be bitfields? Instead of this:
fd = open ( filename, O_RDWR | O_CREAT | O_NDELAY, 0622 );
we'd be using something like this:
Open_flags flags = { 0 }; /* union member ".all" */
File_mode mode = { 0 }; /* union member ".all" */
flags.o.rdwr = O_RDWR;
flags.o.creat = flags.o.ndelay = 1;
mode.s.irwxu = 6; /* Owner */
mode.s.irwxg = mode.s.irwxo = 2; /* Group, user */
fd = open ( filename, flags, mode );
--
Hallvard
Author: dag@control.lth.se (Dag Bruck)
Date: 23 Jun 1994 20:37:56 GMT Raw View
>>>>> "J" == Jim Adcock <jimad@microsoft.com> writes:
J> Yet using enums as bitflags to be or'ed together is a common C
J> programming practice.
C++ enumerations, as defined in the current working paper, actually
provide some significant support for bitflags compared their C
counter-part.
First, C++ enumerators may have values larger than can be represented
by a plain int. For example,
enum Sign {left = -100000, right +100000};
On a PC the underlying representation would typically be a long
integer. In C enumerations are represented by ints.
Second, the C++ working paper goes into some detail to describe what
the minimum representable range is. I will not go into the details,
but the purpose is to make sure that all combinations of enumerators
can be or'd together. All "intermediate" values can be represented, so
clever bit-packing (note that enum Sign would actually only need one
bit if it had Pascal semantics) is not allowed.
Third, a C++ enumeration may in fact occupy _less_ space than an int,
if the implementation so chooses. For example,
enum Season {winter, spring, summer, autumn};
can be represented with a two-bit integer. However, I would expect
that most implementors will pick an int as the smallest representation
to make it easier to mix C and C++ modules.
-- Dag
Author: harrison@sp10.csrd.uiuc.edu (Luddy Harrison)
Date: Thu, 23 Jun 94 20:46:30 GMT Raw View
kanze@us-es.sel.de (James Kanze) writes:
>But in C++, enum's are something more than enumerated types (although
>enumerated types remains an important use). In this context, I'm not
>sure that it wouldn't be better defining `|', `&', `^' and the
>corresponding assignment op's for enum's. If the two operands are of
>the same enum type, the results can always be stored in this type
>without error (according to the working papers).
I don't have the most recent working papers, but this sounds like
a departure from the ARM. From the commentary on p114, section 7.2:
Naturally, one can cast to an enumeration. There is no guarantee,
howver, that the resuling value will be one of the enumerators and
THE VALUE STORED CAN BE IMPLEMENTATION DEPENDENT.
...
The reason arithmetic and logical operations are not defined for
enumerations is that the results of such operations often are NOT
AMONG THE VALUES DEFINED FOR THE ENUMERATORS. (emphasis mine)
By that language, a legal implementation would be to represent the
enumerators as indices 0 .. N-1 (for N enumerators), and to perform
casts to integers by indexing an array that holds the values of
enumerators as integers. In other words, given
enum foo { a=1, b=100000000 };
a foo could be represented using one bit, and the bit would serve
to index an array, effectively
int foovalues[2] = { 1, 100000000 };
A cast from int to foo would be a switch statement or a binary search
on foovalues, whatever.
This may be a terrible idea, but it seems
to me that the language of the ARM permitted it. Logical and arithmetic
operations here make sense only if they produce a value in the enumerated
type (that is, one of the enumerators).
>The major problem I see in this is what to do about `~'. On one hand,
>you want `~', since it is used in the traditional idiom for resetting
>bits. On the other hand, `~ONE', above, may not fit in an `N'. While
>I don't think that the problem is unsurmountable, it does require more
>effort than just saying that the operator is allowed.
Why is ~ more a problem than the other bitwise operators?
If there are k bits, ~ complements all k of them, and you get what you
get, maybe one of the enumerators, maybe not. Any value that
could be produced by ~ could be produced by | or &, where one of the
operands is cast from an integer of the appropriate value.
-Luddy Harrison
Author: jones@cais.cais.com (Ben Jones)
Date: 23 Jun 1994 15:25:17 GMT Raw View
John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: enums are broke in C++ and
: the committee has no intention of fixing them. Use classes
: if you want to have properly enforced contracts.
Why is that?
It seems to me that since they went to all the trouble of making enums create
separate and distinct types they should finish the job. Why not allow
enumerator names to overlap:
enum Light { off, on };
enum Burner { off, low, medium, high };
enum Speed { slow, medium, fast };
so that you can say:
Light l1 = off;
Burner b1 = off;
Speed s1 = medium;
This shouldn't be any more difficult than distinguishing "a" in the
expressions "x.a" and "y.a" where "x" and "y" are objects of completely
different classes. Certainly the compiler could know what names are
available to assign to "l1" and "b1" by looking at their respective
types.
Because C++ does not have this capability, we still have to put up with
keywords with ugly prefixed or qualified names to make sure that they won't
conflict.
Ben Jones
jones@arsoftware.arclch.com
Author: miket@world.std.com (Michael Trachtman)
Date: Fri, 24 Jun 1994 03:02:49 GMT Raw View
James Kanze (kanze@us-es.sel.de) wrote:
: This is only unintuitive if you consider enum's to be enumerated
: types. In the current working papers, in any case, this is not the
: case. While a C++ enum can be used to simulate an enumerated type, it
: is not really an enumerated type in the strict sense of the word.
I agree. If enums were a pure enumerated types, then C++ (and C) would not
allow you to specify the specific values for each of the enumerated types.
I.e. enum colors { red = 23, green = 52 }; would not be allowed.
However, since C++ (and C) do allow you to give specific values, that means
that the languages want you to be able to think of the enums in a dual
fashion: 1) as enumerated types. 2) as specific values.
Given that that is the case, you should be allowed to do arithmetic, etc.
Possibly, if we wanted to be strict, we could disallow
operators like |,&, +, -, if the programmer did not assign specific
values to at least one of the enumerators. However, when the
programmer has specifically says that he is aware and cares about
the values of the enumerators he should be able to do arithmetic
with it, without the compiler arbitrarily converting the
enums to ints. I.e.
The bitfields examples that were posted earlier on should be allowed.
And maybe even the following:
enum COLORS { black = 0, white = 255 };
COLORS grey = (black + white) / 2;
Michael Trachtman
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Fri, 24 Jun 1994 07:33:27 GMT Raw View
kanze@us-es.sel.de (James Kanze) writes:
>Independantly of what you or I or the original poster have to say
>about what constitutes the type `enum color', the value which results
>from `(red|green)' is a legal value for the type `enum color'
>according to the working papers.
Well, the value that results may be a legal value, but the type
that results from `(red|green)' is not `enum color', so you need
to use a cast if you want to assign it to a enum variable.
Unlike the original poster, I think that that is a good thing,
and I don't think that that part of the rules should change.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Fri, 24 Jun 1994 07:49:53 GMT Raw View
kanze@us-es.sel.de (James Kanze) writes:
>fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>
>|> > Wrong. The result of eOne | eTwo is
>
>|> > AtMostTwo(3)
>|> Yes, but this is so unintuitive that you should need to use a cast.
>
>This is only unintuitive if you consider enum's to be enumerated
>types. In the current working papers, in any case, this is not the
>case.
This is not correct, at least according to my interpretation of
the 27th May draft of the working paper. I interpret it to say
that the result of `eOne | eTwo' is an int, not an `enum AtMostTwo',
and I infer that a cast is therefore required.
It says in [expr.or] that the operands of the bitwise or operator are
subject to the usual arithmetic conversions , and the rules for the
usual arithmetic conversions in [conv.arith] specify that "...
otherwise, both operands are int" which implies that enumerations get
promoted to ints and the result type is int.
Has the working paper changed since 27th May?
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: jason@cygnus.com (Jason Merrill)
Date: Fri, 24 Jun 1994 09:11:46 GMT Raw View
>>>>> Luddy Harrison <harrison@sp10.csrd.uiuc.edu> writes:
> I don't have the most recent working papers, but this sounds like
> a departure from the ARM. From the commentary on p114, section 7.2:
The WP says:
**********************
5.2.8 Static cast | [expr.static.cast]
...
6 A value of integral type may be explicitly converted to an enumeration | |
type. The result of the conversion will compare equal to the integral |
value provided that the value is within the range of the enumeration's |
underlying type (7.2). Otherwise, the result is undefined. |
...
7.2 Enumeration declarations [dcl.enum]
...
5 The underlying type of an enumeration is an integral type, not
gratuitously larger than int,[24] that can represent all enumerator |
values defined in the enumeration. If the enumerator-list is empty, |
the underlying type is as if the enumeration had a single enumerator |
with value 0. The value of sizeof() applied to an enumeration type, |
an object of enumeration type, or an enumerator, is the value of
sizeof() applied to the underlying type.
6 For an enumeration where e min is the smallest enumerator and e max is |
the largest, the values of the enumeration are the values of the |
underlying type in the range b min to b max, where b min and b max are, |
respectively, the smallest and largest values of the smallest bit- |
field that can store e min and e max. On a two's-complement machine, |
b max is the smallest value greater than or equal to |
max(abs(e min),abs(e max)) of the form 2M-1; b min is zero if e min is |
non-negative and -(b max+1) otherwise. It is possible to define an |
enumeration that has values not defined by any of its enumerators.
7 The value of an enumerator or an object of an enumeration type is |
converted to an integer by integral promotion (4.1). For example,
enum color { red, yellow, green=20, blue };
color col = red;
color* cp = &col;
if (*cp == blue) // ...
makes color a type describing various colors, and then declares col
as an object of that type, and cp as a pointer to an object of that
type. The possible values of an object of type color are red,
yellow, green, blue; these values can be converted to the integral
values 0, 1, 20, and 21. Since enumerations are distinct types,
objects of type color may be assigned only values of type color.
For example,
color c = 1; // error: type mismatch,
// no conversion from int to color
int i = yellow; // ok: yellow converted to integral value 1
// integral promotion
See also C.3.
8 An expression of arithmetic type or of type wchar_t may 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.
+------- BEGIN BOX 34 -------+
This means the program does not crash.
+------- END BOX 34 -------+
************************
> By that language, a legal implementation would be to represent the
> enumerators as indices 0 .. N-1 (for N enumerators), and to perform
> casts to integers by indexing an array that holds the values of
> enumerators as integers. In other words, given
> enum foo { a=1, b=100000000 };
> a foo could be represented using one bit, and the bit would serve
> to index an array, effectively
> int foovalues[2] = { 1, 100000000 };
> A cast from int to foo would be a switch statement or a binary search
> on foovalues, whatever.
Author: kanze@us-es.sel.de (James Kanze)
Date: 24 Jun 1994 14:16:40 GMT Raw View
In article <1994Jun23.204630.21057@csrd.uiuc.edu>
harrison@sp10.csrd.uiuc.edu (Luddy Harrison) writes:
|> kanze@us-es.sel.de (James Kanze) writes:
|> >But in C++, enum's are something more than enumerated types (although
|> >enumerated types remains an important use). In this context, I'm not
|> >sure that it wouldn't be better defining `|', `&', `^' and the
|> >corresponding assignment op's for enum's. If the two operands are of
|> >the same enum type, the results can always be stored in this type
|> >without error (according to the working papers).
|> I don't have the most recent working papers, but this sounds like
|> a departure from the ARM. From the commentary on p114, section 7.2:
|> Naturally, one can cast to an enumeration. There is no guarantee,
|> howver, that the resuling value will be one of the enumerators and
|> THE VALUE STORED CAN BE IMPLEMENTATION DEPENDENT.
|> ...
|> The reason arithmetic and logical operations are not defined for
|> enumerations is that the results of such operations often are NOT
|> AMONG THE VALUES DEFINED FOR THE ENUMERATORS. (emphasis mine)
|> By that language, a legal implementation would be to represent the
|> enumerators as indices 0 .. N-1 (for N enumerators), and to perform
|> casts to integers by indexing an array that holds the values of
|> enumerators as integers. In other words, given
|> enum foo { a=1, b=100000000 };
|> a foo could be represented using one bit, and the bit would serve
|> to index an array, effectively
|> int foovalues[2] = { 1, 100000000 };
|> A cast from int to foo would be a switch statement or a binary search
|> on foovalues, whatever.
This is a departure from the ARM, and is in the current working
papers. I don't have my copy handy to quote, but Dag Bruck gave a
good explination of the current status in another post. Basically,
the values are used to determine the minimum number of bits needed,
and then all values which will fit into those bits are defined as
legal.
|> This may be a terrible idea, but it seems
|> to me that the language of the ARM permitted it. Logical and arithmetic
|> operations here make sense only if they produce a value in the enumerated
|> type (that is, one of the enumerators).
|> >The major problem I see in this is what to do about `~'. On one hand,
|> >you want `~', since it is used in the traditional idiom for resetting
|> >bits. On the other hand, `~ONE', above, may not fit in an `N'. While
|> >I don't think that the problem is unsurmountable, it does require more
|> >effort than just saying that the operator is allowed.
|> Why is ~ more a problem than the other bitwise operators?
|> If there are k bits, ~ complements all k of them, and you get what you
|> get, maybe one of the enumerators, maybe not. Any value that
|> could be produced by ~ could be produced by | or &, where one of the
|> operands is cast from an integer of the appropriate value.
Author: kanze@us-es.sel.de (James Kanze)
Date: 24 Jun 1994 14:27:42 GMT Raw View
In article <9417517.4351@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU
(Fergus Henderson) writes:
|> kanze@us-es.sel.de (James Kanze) writes:
|> >Independantly of what you or I or the original poster have to say
|> >about what constitutes the type `enum color', the value which results
|> >from `(red|green)' is a legal value for the type `enum color'
|> >according to the working papers.
|> Well, the value that results may be a legal value, but the type
|> that results from `(red|green)' is not `enum color', so you need
|> to use a cast if you want to assign it to a enum variable.
|> Unlike the original poster, I think that that is a good thing,
|> and I don't think that that part of the rules should change.
Currently, the type of `(red|green)' is int. As I understand the
discussion, we are considering the desirability of making it `enum
color'. My point was simply that the argument that such values may be
somehow "out of range." was not valid.
This said, I think I agree with you (although I don't feel strongly
either way). When I use an enum as an enumerated type, I *don't* want
such operations to be legal, and when I use it otherwise (which occurs
relatively frequently), it is no big deal to overload the
corresponding operators for that particular enum.
Another poster suggested that such operators be legal if at least one
of the enumerated constants was explicitly given, and illegal
otherwise. While I like this idea in theory, it introduces two
"flavors" of enum types, which in turn filter into the type system
somehow (to change the type of the results of certain operations). So
it looks like it is more trouble than it is worth, especially as I
would like to see a standard before the end of the century.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: kanze@us-es.sel.de (James Kanze)
Date: 24 Jun 1994 14:41:59 GMT Raw View
In article <9417517.4839@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU
(Fergus Henderson) writes:
|> kanze@us-es.sel.de (James Kanze) writes:
|> >fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
|> >
|> >|> > Wrong. The result of eOne | eTwo is
|> >
|> >|> > AtMostTwo(3)
|> >|> Yes, but this is so unintuitive that you should need to use a cast.
|> >
|> >This is only unintuitive if you consider enum's to be enumerated
|> >types. In the current working papers, in any case, this is not the
|> >case.
|> This is not correct, at least according to my interpretation of
|> the 27th May draft of the working paper. I interpret it to say
|> that the result of `eOne | eTwo' is an int, not an `enum AtMostTwo',
|> and I infer that a cast is therefore required.
I never said the contrary. I simply said that C/C++ enum's are *not*
enumerated types. In a certain sense, a true enumerated type has no
numeric value, and so or'ing or and'ing them would be an undefined
operation. (Or'ing or and'ing sets of enumerated types would be
reasonable, however.)
In C/C++, enum constants are simply named *integral* constants of a
user specified *integral* type. The results of or'ing or and'ing them
are defined by the rules of integral promotion, since the numeric
values of the constants are defined.
As such, it makes perfect sense to discuss whether e.g. |= should be
allowed on such types. It is allowed on other subranges of int (for
example, char), although integral promotion also takes place here.
The decision to ban |=, etc., and to state that an int will not
implicitly convert to an enum, is in a certain sense arbitrary. There
is certainly nothing counter-intuitive with the alternative. The
decision should be based on the perceived advantages to the programmer
of each of the two alternatives.
Given that one of the more frequent uses of enum types is to simulate
enumerated types, and that it is trivial to add the operators if and
when you so desire (by operator overloading on enum), I think that the
status quo is the preferred alternative. But I certainly wouldn't
claim that people who think differently are somehow recommending
something counter-intuitive.
--
James Kanze email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 20 Jun 1994 07:08:54 GMT Raw View
In article <CrnEJH.7Ju@world.std.com> miket@world.std.com (Michael Trachtman) writes:
>I think that when the enum are being used as bitfields, it is clear that
> e1 |= e2 as well as e1 &= e2 are perfectly "type safe".
>
>The inputs and the outputs are of the same type...
I'm sorry, but neither of your assertions (quoted here) are the least bit
clear... at least not to me.
Take a simple example:
enum colors { red = 1, green = 2, orange = 77 };
Given that definition, what `type' should the value of
(red | green)
be said to have?
(If you say `enum color' then I'll just have to observe that you and I
disagree about what should and what should not be considered to be a value
of type `enum color'.)
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 20 Jun 1994 10:06:57 GMT Raw View
miket@world.std.com (Michael Trachtman) writes:
>Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
>: What's wrong with using
>: enum { BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004 };
[...]
>The purpose of doing it my way is extra type safety.
Ah, but in order for you to get your extra type safety, you
want to take away type safety in the ordinary case where
enums are being used as enumerations, not as powersets,
by allowing operations which fall outside the range of the
enumeration.
My advice is that you should use a bitset<T> class which just encapsulates
an int. Then you can write code like
enum Flag { RedFlag, GreenFlag, BlueFlag };
// look ma, no magic numbers ;-)
bitset<Flag> flags1;
bitset<Flag> flags2(RedFlag);
flags1.set(GreenFlag);
flags2.unset(RedFlag);
bitset<Flag> flags = flags1 + flags2; // set union
and will get all the type-safety you want, right?
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 20 Jun 1994 16:01:53 +0000 Raw View
In article <Cro7BL.64K@world.std.com>
miket@world.std.com "Michael Trachtman" writes:
>Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
>: What's wrong with using
>
>: enum { BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004 };
>
>: or
>
>: const int BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004;
>
>Thhe purpose of doing it my way is extra type safety.
>
>Suppose I have two sets of flags.
>
>typedef enum { CHOCOLATE = 0x01, VANILLA = 0x02, STRAWBERRY=0x04 } FLAVORS;
>
>typedef enum { CHOCOLATE = 0x01, SPRINKLES = 0x02, WHIPPING_CREAM = 0x04}
> TOPPINGS;
No typedef reqd :-)
>I then want to have a structure:
> typedef structure {
> FLAVORS flavors;
> TOPPINGS toppings;
> } PRODUCT;
>
> I would like to say:
>
> PRODUCT product;
>
> product.flavors = CHOCOLATE | STRAWBERRY;
> product.toppings = CHOCOLATE | WHIPPING_CREAM;
>
>I would the compiler to flag me if I say:
> product.flavors |= WHIPPING_CREAM;
>or product.flavors = product.toppings;
>
>Using enums gives me type safety.
By breaking the type system? Surely not. The above code fails to distinguish
between containers and containees. The enums are the containees and a var
of an enum specifies exactly ONE enum. Period. If you wish to group them
together you are welcome to use an appropriate container: unsigned int,
bitset, bitstring, or even dynarray and strstream, or any other appropriate
encoding mechanism, ie. not an enum.
That C allows you to treat enums as identical w/ ints is a fault w/ C. That
the programmer wants to do it like this is a fault w/ the programmer ;-)
It is at very least a conceptual type error, and at best (as C++ correctly
identifies) a static type error.
--
Kevlin Henney
repeat 3 echo there\'s no place like ~
Author: miket@world.std.com (Michael Trachtman)
Date: Wed, 22 Jun 1994 03:56:21 GMT Raw View
John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: In particular, whats wrong with
: template <class E> E operator |=(E e1, E e2)
: { return e=E(e1|e2); }
: which allows you to write
: e |= e2
: if you want?
WOW !!! Neato !!! Cool !!!!
A polymorphic language. If you don't like the type rules of the language,
then change them to suit your needs. WOW...
I'm not sure I understand all the ramifications. But still, this is COOL.
Thanx John Max....
Michael T.
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Wed, 22 Jun 1994 21:30:32 GMT Raw View
In article <50@kaulakis.win.net> ekaulaki@kaulakis.win.net (Edward C. Kaulakis) writes:
>
>What we seem to be talking about is a traditional asm idiom where
>x, an enum item, and {x}, a powerset over the enum, have the same
>bit encodings, chosen to allow hardware-efficient implementation of
>eg.
>
>PowerSet += EnumItem;
>PowerSet -= OtherPowerSet;
>
>My point is that the enum and its powerset are different types. And
>while ONE and TWO are enum items, THREE is a powerset.
>
>This distinction matters. By making it explict, we embed in the
>source our contract not to create any enum members with more than
>1 bit on in their encoding.
Nice analysis. Answer: enums are broke in C++ and
the committee has no intention of fixing them. Use classes
if you want to have properly enforced contracts.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Wed, 22 Jun 1994 22:56:27 GMT Raw View
In article <Crs5Ly.8tt@world.std.com> miket@world.std.com (Michael Trachtman) writes:
>John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
>: In particular, whats wrong with
>
>: template <class E> E operator |=(E e1, E e2)
>: { return e=E(e1|e2); }
>
>: which allows you to write
>
>: e |= e2
>
>: if you want?
>
>
>WOW !!! Neato !!! Cool !!!!
>
>I'm not sure I understand all the ramifications. But still, this is COOL.
I'm not sure I understand all the ramifications either.
Note that template is universal. It "works" for classes which
define "|" too. What happens if the class ALSO defines |= ??
What happens if |= doesn't make sense for an intended
interpretation of some enum -- normally you'd get an error,
but with the template you have a silent application of
an inappropriate function.
[One of my programmers used this template with no problems,
thats all I can say, it doesnt mean much]
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: jones@cais.cais.com (Ben Jones)
Date: 22 Jun 1994 14:10:38 GMT Raw View
Michael Trachtman (miket@world.std.com) wrote:
: John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: : In particular, whats wrong with
: : template <class E> E operator |=(E e1, E e2)
: : { return e=E(e1|e2); }
: : which allows you to write
: : e |= e2
: : if you want?
Why don't they just allow arithmetic expressions between enumerated types
and arithmetic types to promote to the enumerated type:
enum E {a,b,c};
E e1 = a;
e1++; // e1 = b
e1 += 1; // e1 = c
for (E e2=a;e2<c;e2++) ...
The compiler could still complain about mixing enumerated types and about
assignment of arithmetic types to enumerated types (unless explicitly cast).
Ben Jones
jones@arsoftware.arclch.com
Author: jason@cygnus.com (Jason Merrill)
Date: Fri, 17 Jun 1994 20:53:59 GMT Raw View
>>>>> David Sachs <b91926@fsgi01.fnal.gov> writes:
> If you wish to handle operations on an enum type, you probably
> should provide overloaded operator functions to do so. This is
> a post-ARM addition to C++.
This is also unnecessary overhead; if I have two enums ONE and TWO with
values of 1 and 2, I want to be able to use the built-in | operator to
combine them into THREE.
Jason
Author: miket@world.std.com (Michael Trachtman)
Date: Fri, 17 Jun 1994 22:20:11 GMT Raw View
It could be that the ARM defines the result of applying |
to two items of an enum type as an integer. However,
if the ARM does so, then it is unreasonable.
Code like: a |= b; a = a | b; as well as c = (a & b) ? a | b;
should be allowed if a, b and c are of the same enum type.
There is no reason to convert to int at any point.
Does anyone have a strong argument as to why a conversion to int
should be done when all the expression elements
are of the same enum type. ??
Not to mention, that as far as I know, it is legal C,
and should therefore be kept for backward compatability reasons.
In addition, I am still at a loss to explain the compiler.
Why does it allow: (a = a | b) and disallows (a |= b) ??
Finally, if there is no good reason for the current behavior,
how do I propose to the comittee to allow the behavior
that I think is reasonable ??
Michael Trachtman
John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
: In article <CrJ0C6.BEB@world.std.com> miket@world.std.com (Michael Trachtman) writes:
: >
: >I am unclear about the legality of using the |, |=, & and &=
: >operators with enums. In particular, I have tried variants of
: >the following program using various compilers. Each did not like
: >at least one of the lines of code.
: | and & can be applied to enums and cause conversions
: to integral types.
: |= and &= cannot be applies to enums, they require
: an lvalue on the LHS of the enum type, but the form
: a |= b
: expands to
: a = a | b
: and the RHS of that is an integral type. The assignment:
: enum_obj = int_obj;
: is not permitted, you cant convert an integral type to an
: enum type automatically (you can explicitly).
Author: jason@cygnus.com (Jason Merrill)
Date: Sat, 18 Jun 1994 01:38:09 GMT Raw View
>>>>> John Max Skaller <maxtal@physics.su.OZ.AU> writes:
> In article <JASON.94Jun17040720@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>> values of enum type when applied to enum arguments. However, the current
>> WP specifies that the usual arithmetic promotions are applied to the
>> operands of | and &, which means they are promoted to int, and there is no
>> standard conversion from int to an enumeral type. This situation is
>> probably an oversight.
> Its not. Its deliberate. You cant convert an int to an enum
> implicitly.
I wasn't referring to implicit conversion of int to enum in general, I was
referring to doing bitwise arithmetic on enums and storing the value in an
enum. I guess I should have been clearer.
Jason
Author: itz@crl.com (Ian T. Zimmerman)
Date: 17 Jun 1994 21:43:30 -0700 Raw View
In article <CrKBDo.6D0@world.std.com>,
Michael Trachtman <miket@world.std.com> wrote:
>
>Does anyone have a strong argument as to why a conversion to int
>should be done when all the expression elements
>are of the same enum type. ??
>
Yes, I believe here's an excellent argument for it:
enum AtMostTwo { eZero, eOne, eTwo };
AtMostTwo Fudge (void) { return (eOne | eTwo); }
...
AtMostTwo amt;
...
amt = Fudge ();
switch (amt) {
case eZero:
Foo (); break;
case eOne:
Bar (); break;
case eTwo:
Foobar (); break;
default:
throw (OutOfRange ());
}
...
catch (OutOfRange e)
{
abort ("Internal error, call tech support"); //entirely reasonable
}
IMHO, this is just a coding manifestation of a problem on a more abstract
semantic (aesthetic?) level. The bitwise operations simply do not
correspond to any well-defined algebraic operators on the _type_
AtMostTwo. Or, to turn it around, if you want them, you forfeit the right
to consider enums as first-class types.
BTW, I do believe that the compiler goofed in the case quoted by the
original post. It should have complained about line 3 too. The rest was
correctly accepted as can be explained by the conversion to int.
--
Ian T Zimmerman +-------------------------------------------+
P.O. Box 13445 I With so many executioners available, I
Berkeley, California 94712 I suicide is a really foolish thing to do. I
USA +-------------------------------------------+
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sat, 18 Jun 1994 08:15:57 GMT Raw View
jason@cygnus.com (Jason Merrill) writes:
>>>>>> David Sachs <b91926@fsgi01.fnal.gov> writes:
>
>> If you wish to handle operations on an enum type, you probably
>> should provide overloaded operator functions to do so. This is
>> a post-ARM addition to C++.
>
>This is also unnecessary overhead; if I have two enums ONE and TWO with
>values of 1 and 2, I want to be able to use the built-in | operator to
>combine them into THREE.
By "overhead" I presume you mean an overhead of time/space at runtime.
But there needn't be any runtime overhead involved - just make the
operator an inline function.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 18 Jun 1994 08:23:55 GMT Raw View
In article <JASON.94Jun17040720@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>>>>>> Michael Trachtman <miket@world.std.com> writes:
>
>> The elements on each side of the operators are of the same type,
>> and there is a reasonable and clear meaning of what is done.
>
>I agree with this argument; it makes sense for these operators to return
>values of enum type when applied to enum arguments. However, the current
>WP specifies that the usual arithmetic promotions are applied to the
>operands of | and &, which means they are promoted to int, and there is no
>standard conversion from int to an enumeral type. This situation is
>probably an oversight.
Gosh, I hope not!
This was (I think) part of the whole point behind making enums more `type
safe' in C++. Now (in C++) there are *many* operations (including +, -, *,
/, %, &, |, etc) which you can only do on enums *after* they have been
implicitly promoted to ints.
Look, C++ made it invalid to do:
a += b;
where `a' and 'b' are variables of some given enum type. THIS WAS INTENTIONAL.
Likewise, in C++ you are also not allowed to do:
a &= b;
for similar reasons. So what's wrong with that? I like it. It's called
`type safety'. (It's just too bad the new built-in bool type isn't nearly
so smart. Oh well. I can still use `enum Bool { False, True };'.)
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: jason@cygnus.com (Jason Merrill)
Date: Sat, 18 Jun 1994 11:06:50 GMT Raw View
>>>>> Fergus Henderson <fjh@munta.cs.mu.OZ.AU> writes:
> jason@cygnus.com (Jason Merrill) writes:
>>>>>>> David Sachs <b91926@fsgi01.fnal.gov> writes:
>>
>>> If you wish to handle operations on an enum type, you probably
>>> should provide overloaded operator functions to do so. This is
>>> a post-ARM addition to C++.
>>
>> This is also unnecessary overhead; if I have two enums ONE and TWO with
>> values of 1 and 2, I want to be able to use the built-in | operator to
>> combine them into THREE.
> By "overhead" I presume you mean an overhead of time/space at runtime.
> But there needn't be any runtime overhead involved - just make the
> operator an inline function.
No, really I meant programmer overhead. I just don't think that the extra
verbosity of
inline MyEnum operator| (MyEnum a, MyEnum b) { return MyEnum(int(a)|int(b)); }
makes the intent of the code any clearer.
Jason
Author: harrison@sp10.csrd.uiuc.edu (Luddy Harrison)
Date: 18 Jun 1994 17:37:14 GMT Raw View
Ron Guilmette writes, concerning bitwise operations on enum types:
>> Look, C++ made it invalid to do:
>> a += b;
>> where `a' and 'b' are variables of some given enum type.
>> THIS WAS INTENTIONAL.
>> Likewise, in C++ you are also not allowed to do:
>> a &= b;
>> for similar reasons. So what's wrong with that? I like it. It's called
>> `type safety'
This is one of those rare instances in which the compiler has enough
information to do a run-time test to validate the result of the
operation (namely, that a|b produces a value that is in the enum
type). I've often wished that such operations were legal, and that a
command-line option were available to turn on checking for the
result. As it is, I end up writing a = MyEnum(a|b), which isn't
checked (it could be, but it isn't), and I don't have any type safety
at all, just a cast that looks superfluous.
Similarly, the operator
inline MyEnum operator|(MyEnum a, MyEnum b) { return MyEnum(int(a)|int(b)); }
is no safer than a | b would be (if it returned a MyEnum without checking the
result). They do the same thing.
-Luddy Harrison
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sat, 18 Jun 1994 23:21:28 GMT Raw View
>> If you wish to handle operations on an enum type, you probably
>> should provide overloaded operator functions to do so. This is
>> a post-ARM addition to C++.
>
>This is also unnecessary overhead; if I have two enums ONE and TWO with
>values of 1 and 2, I want to be able to use the built-in | operator to
>combine them into THREE.
You cant, and there is no overhead in theory if you
use an inline. Specifically, try an inline template function:
template<class E> E operator|=(E e1, E e2)
{
return e1=E(e1|e2);
}
but its hard to know if this works correctly because the ARM and
WP do not contain proper rules for the interaction of built-in
and user defined functions by overload resolution. (This is being
worked on).
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 19 Jun 1994 01:37:17 GMT Raw View
In article <2ttu1i$j8p@crl2.crl.com> itz@crl.com (Ian T. Zimmerman) writes:
>In article <CrKBDo.6D0@world.std.com>,
>Michael Trachtman <miket@world.std.com> wrote:
>>
>>Does anyone have a strong argument as to why a conversion to int
>>should be done when all the expression elements
>>are of the same enum type. ??
>>
>Yes, I believe here's an excellent argument for it:
>
>enum AtMostTwo { eZero, eOne, eTwo };
>AtMostTwo Fudge (void) { return (eOne | eTwo); }
>...
>IMHO, this is just a coding manifestation of a problem on a more abstract
>semantic (aesthetic?) level. The bitwise operations simply do not
>correspond to any well-defined algebraic operators on the _type_
>AtMostTwo. Or, to turn it around, if you want them, you forfeit the right
>to consider enums as first-class types.
Wrong. The result of eOne | eTwo is
AtMostTwo(3)
which is a perfectly valid value of the enum you have misnamed
'AtMostTwo'. The range of values of an enum is the same as the
smallest bitfield that could contain the enumerators,
the underlying type is "unsigned" something unless an enumerator
is negative in which case the underlying type is "signed" something.
Unless you have a copy of the WP you could not know this.
(Does D&E mention it? I dont have a copy yet)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 19 Jun 1994 01:51:54 GMT Raw View
In article <JASON.94Jun17183809@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>> Its not. Its deliberate. You cant convert an int to an enum
>> implicitly.
>
>I wasn't referring to implicit conversion of int to enum in general, I was
>referring to doing bitwise arithmetic on enums and storing the value in an
>enum. I guess I should have been clearer.
Consider an enum with no negative values. Then
e1 |= e2
e1 &= e2
are well defined -- the result is guarranteed to be a value in
the range of the enum (exactly because enums are addressable bitfields).
If this was defined, you would not be allowed to write user defined
operators |= and &=. This is already true for assignment of enums.
But
e1 += e2
~ e
etc etc are NOT well defined for enums. Its better to allow ALL
the operators to be overloaded by the user (other than assignment?)
than get the compiler to generate just the four that happen to be
guarranteed to work. (e1 | e2 and e1 & e2 also work).
On the other hand, I'm unsure about negative values, such an enum
uses a signed underlying type -- and their representation
is not well defined bitwise, so its unclear to me what even
e1 |= e2
e1 & = e2
would mean -- and thus if they really are guarranteed to be in range.
(I mean I'm too lazy to figure it out :-)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 19 Jun 1994 02:06:29 GMT Raw View
In article <HARRISON.94Jun18123715@sp10.csrd.uiuc.edu> harrison@sp10.csrd.uiuc.edu (Luddy Harrison) writes:
>Ron Guilmette writes, concerning bitwise operations on enum types:
>
>>> Look, C++ made it invalid to do:
>>> a += b;
>>> where `a' and 'b' are variables of some given enum type.
>>> THIS WAS INTENTIONAL.
>>> Likewise, in C++ you are also not allowed to do:
>>> a &= b;
>>> for similar reasons. So what's wrong with that? I like it. It's called
>>> `type safety'
>
>This is one of those rare instances in which the compiler has enough
>information to do a run-time test to validate the result of the
>operation (namely, that a|b produces a value that is in the enum
>type).
Yes, but that would cost cycles. Do I want to pay that price in *my*
deployed code? No way.
(Implementations could also universally check for integer overflow, but
in general they don't... for similar reasons.)
>I've often wished that such operations were legal, and that a
>command-line option were available to turn on checking for the
>result.
You may want to mention your desires to either Pure Software Inc. or to
Centerline. Perhaps they will build something to accomodate you... at
least during the *development* part of the cycle (as opposed to deployment).
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sun, 19 Jun 1994 07:06:43 GMT Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>In article <2ttu1i$j8p@crl2.crl.com> itz@crl.com (Ian T. Zimmerman) writes:
>>enum AtMostTwo { eZero, eOne, eTwo };
>>AtMostTwo Fudge (void) { return (eOne | eTwo); }
>>...
>>IMHO, this is just a coding manifestation of a problem on a more abstract
>>semantic (aesthetic?) level. The bitwise operations simply do not
>>correspond to any well-defined algebraic operators on the _type_
>>AtMostTwo. Or, to turn it around, if you want them, you forfeit the right
>>to consider enums as first-class types.
>
> Wrong. The result of eOne | eTwo is
>
> AtMostTwo(3)
Yes, but this is so unintuitive that you should need to use a cast.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: miket@world.std.com (Michael Trachtman)
Date: Sun, 19 Jun 1994 14:08:28 GMT Raw View
John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
[stuff deleted.
: On the other hand, I'm unsure about negative values, such an enum
: uses a signed underlying type -- and their representation
: is not well defined bitwise, so its unclear to me what even
: e1 |= e2
: e1 & = e2
: would mean -- and thus if they really are guarranteed to be in range.
: (I mean I'm too lazy to figure it out :-)
They mean the same as:
int /* signed */ i1, i2;
i1 |= i2; i1 &= i2;
The actual value may depend on the hardware. For almost allmost hardware that
uses standard two's complement arithmetic, the result would be the same.
John, if you agree that enum types are allowed values that are not in
the original enum set, then do you agree that e1 |= e2, should be legal
C++, in fact it should be an encouraged idiom, so that people move away
from using #define BIT1 0x0001, and: int flags;
Michael T.
Author: miket@world.std.com (Michael Trachtman)
Date: Sun, 19 Jun 1994 14:21:17 GMT Raw View
I would like to comment on Ron's comments. I would like to then
recommend a new idea on how C++ can handle this situation
of |= and &= for enums.
Ronald F. Guilmette (rfg@netcom.com) wrote:
: >>>>>> Michael Trachtman <miket@world.std.com> writes:
: >> The elements on each side of the operators are of the same type,
: >> and there is a reasonable and clear meaning of what is done.
: >
: This was (I think) part of the whole point behind making enums more `type
: safe' in C++. Now (in C++) there are *many* operations (including +, -, *,
: /, %, &, |, etc) which you can only do on enums *after* they have been
: implicitly promoted to ints.
: Likewise, in C++ you are also not allowed to do:
: a &= b;
: for similar reasons. So what's wrong with that? I like it. It's called
: `type safety'.
I think that when the enum are being used as bitfields, it is clear that
e1 |= e2 as well as e1 &= e2 are perfectly "type safe".
The inputs and the outputs are of the same type. They have well understood
meanings. The meaning is clear. It should be a standard idiom.
And the language should encourage using enums for bitfields,
rather than ints and #defines, or superfluous casting.
(e.g. a = (FLAGS) a & b;).
I would argue that e1 += e2 is also typesafe. If is just a less likely
situation.
Possibly, what is needed is a notation for enums which lets the compiler
know whether values that are not enumerated are legal values for the enum.
As a first suggestion, how about....
typedef enum
{
BIT1 = 0x0001,
BIT2 = 0x0002,
BIT3 = 0x0004,
BIT4 = 0x0008,
BIT0 = 0x0000, /* first legal value */
..., /* All values in this range are allowed. */
BIT_LAST = 0x00F /* Allow 0x0000 through 0x000f */
} BITS;
The language can be defined to use this syntax for allowed ranged.
Arithmetic operations would throw exceptions if a result is out of range.
No checking would be needed if you give a range of 0x0000-0xffff.
Michael T.
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sun, 19 Jun 1994 14:57:10 GMT Raw View
miket@world.std.com (Michael Trachtman) writes:
>John, if you agree that enum types are allowed values that are not in
>the original enum set, then do you agree that e1 |= e2, should be legal
>C++, in fact it should be an encouraged idiom, so that people move away
>from using #define BIT1 0x0001, and: int flags;
Yes, we want to discourage people from using #define
and encourage them to enumeration constants or ordinary constants,
but that doesn't mean that `flags' must be declared as an
enum. What's wrong with using
enum { BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004 };
or
const int BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004;
and then just using
int flags = BIT1;
flags |= BIT2;
flags &= BIT3;
or alternatively using something like
enum { BIT1, BIT2, BIT3 };
bitset flags(BIT1);
flags.set(BIT2);
flags.unset(BIT3);
?
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 19 Jun 1994 18:58:12 GMT Raw View
In article <CrnEJH.7Ju@world.std.com> miket@world.std.com (Michael Trachtman) writes:
>
>And the language should encourage using enums for bitfields,
>rather than ints and #defines, or superfluous casting.
>(e.g. a = (FLAGS) a & b;).
When the rules were layed down ALL the common idioms
were carefully considered -- bits, ranges, sets of named types, etc.
>
>I would argue that e1 += e2 is also typesafe. If is just a less likely
>situation.
Only if the arithmetic were modular.
>
>Possibly, what is needed is a notation for enums which lets the compiler
>know whether values that are not enumerated are legal values for the enum.
What we need is to not use C's broken enums. :-(
>The language can be defined to use this syntax for allowed ranged.
>Arithmetic operations would throw exceptions if a result is out of range.
>No checking would be needed if you give a range of 0x0000-0xffff.
Just write a class. Thats how to use enums -- wrap them
in a class :-(
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 19 Jun 1994 18:54:33 GMT Raw View
In article <CrnDy5.5y8@world.std.com> miket@world.std.com (Michael Trachtman) writes:
>John Max Skaller (maxtal@physics.su.OZ.AU) wrote:
>
>[stuff deleted.
>
>John, if you agree that enum types are allowed values that are not in
>the original enum set,
Its not a question of what I agree to, but what the Working
Paper actually says. As I understand it, enum ranges are like
bitfields to enable fast checking on conversions from integral types
to the enum.
>then do you agree that e1 |= e2, should be legal
>C++, in fact it should be an encouraged idiom, so that people move away
>from using #define BIT1 0x0001, and: int flags;
I dont agree -- yet. I see arguments against it.
In particular, whats wrong with
template <class E> E operator |=(E e1, E e2)
{ return e=E(e1|e2); }
which allows you to write
e |= e2
if you want?
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: bs@alice.att.com (Bjarne Stroustrup)
Date: 19 Jun 94 20:28:47 GMT Raw View
jason@cygnus.com (Jason Merrill @ Cygnus Support, Mountain View, CA) writes
> >>>>> David Sachs <b91926@fsgi01.fnal.gov> writes:
>
> > If you wish to handle operations on an enum type, you probably
> > should provide overloaded operator functions to do so. This is
> > a post-ARM addition to C++.
>
> This is also unnecessary overhead; if I have two enums ONE and TWO with
> values of 1 and 2, I want to be able to use the built-in | operator to
> combine them into THREE.
Hmm. Are you sure that is always a good idea?
Consider:
enum N { ONE=1, TWO, THREE, FOUR };
The value of ONE|TWO is 3 which just happenss to be the value of THREE.
However, TWO|THREE doesn't have the same value as FOUR. In fact, TWO|THREE
doesn't have a value that is representable as an N.
Exactly how to generalize the usual arithmetical and logical operations to
apply to enumerations is not obvious.
Author: miket@world.std.com (Michael Trachtman)
Date: Mon, 20 Jun 1994 00:42:57 GMT Raw View
Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
: What's wrong with using
: enum { BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004 };
: or
: const int BIT1 = 0x0001, BIT2 = 0x0002, BIT3 = 0x0004;
Thhe purpose of doing it my way is extra type safety.
Suppose I have two sets of flags.
typedef enum { CHOCOLATE = 0x01, VANILLA = 0x02, STRAWBERRY=0x04 } FLAVORS;
typedef enum { CHOCOLATE = 0x01, SPRINKLES = 0x02, WHIPPING_CREAM = 0x04}
TOPPINGS;
I then want to have a structure:
typedef structure {
FLAVORS flavors;
TOPPINGS toppings;
} PRODUCT;
I would like to say:
PRODUCT product;
product.flavors = CHOCOLATE | STRAWBERRY;
product.toppings = CHOCOLATE | WHIPPING_CREAM;
I would the compiler to flag me if I say:
product.flavors |= WHIPPING_CREAM;
or product.flavors = product.toppings;
Using enums gives me type safety.
Michael T.
Author: ekaulaki@kaulakis.win.net (Edward C. Kaulakis)
Date: Sun, 19 Jun 1994 23:14:23 GMT Raw View
In article <JASON.94Jun17135359@deneb.cygnus.com>, Jason Merrill (jason@cygnus.com) writes:
>>>>>> David Sachs <b91926@fsgi01.fnal.gov> writes:
>
>> If you wish to handle operations on an enum type, you probably
>> should provide overloaded operator functions to do so. This is
>> a post-ARM addition to C++.
>
>This is also unnecessary overhead; if I have two enums ONE and TWO with
>values of 1 and 2, I want to be able to use the built-in | operator to
>combine them into THREE.
Hmm. Should | complain if THREE isn't in your enum? What should it
do with TWO and THREE?
What we seem to be talking about is a traditional asm idiom where
x, an enum item, and {x}, a powerset over the enum, have the same
bit encodings, chosen to allow hardware-efficient implementation of
eg.
PowerSet += EnumItem;
PowerSet -= OtherPowerSet;
My point is that the enum and its powerset are different types. And
while ONE and TWO are enum items, THREE is a powerset.
This distinction matters. By making it explict, we embed in the
source our contract not to create any enum members with more than
1 bit on in their encoding.
--
Edward C. Kaulakis (Voice)(805)296-0303
21847 Agajanian Ln., (Fax) (805)296-4718
Santa Clarita CA 91350 ekaulaki@kaulakis.win.net
I *sell* my opinions. But for you, a special price!
Author: miket@world.std.com (Michael Trachtman)
Date: Fri, 17 Jun 1994 05:24:05 GMT Raw View
I am unclear about the legality of using the |, |=, & and &=
operators with enums. In particular, I have tried variants of
the following program using various compilers. Each did not like
at least one of the lines of code.
Specifically, the Borland 4.0 compiler complained (warning) only about the
line abc |= X2;. It did not complain about any of the other lines.
I don't get it. If that line is incorrect, then so should the next line.
(And so should the lines with the binary & operator.)
It seems to me that all these lines of code should be correct.
The elements on each side of the operators are of the same type,
and there is a reasonable and clear meaning of what is done.
Since enums allow you to assign the specific values for the
enumerated items, it should allow you to deal with their
bit representation.
Especially since there is a stated goal (in D&E) of moving away from #define.
What does "official" c++ say about this code ??
#include <stdio.h>
typedef enum
{
X0 = 0x0000,
X1 = 0x0001,
X2 = 0x0002,
X3 = 0x0004,
X4 = 0x0008,
X5 = 0x0010
} BITS;
int
main()
{
BITS abc;
abc = X0;
abc |= X2; /* compiler complains about this line */
abc = abc | X3; /* compiler DOES not complain about this line. */
/* Compiler does not complain about any of the following uses of the
* binary '&' operator.
*/
if (abc & X1)
printf("X1 is on.\n");
if (abc & X2)
printf("X2 is on.\n");
if (abc & X3)
printf("X3 is on.\n");
if (abc & X4)
printf("X4 is on.\n");
return 0;
};
Author: jason@cygnus.com (Jason Merrill)
Date: Fri, 17 Jun 1994 11:07:20 GMT Raw View
>>>>> Michael Trachtman <miket@world.std.com> writes:
> The elements on each side of the operators are of the same type,
> and there is a reasonable and clear meaning of what is done.
I agree with this argument; it makes sense for these operators to return
values of enum type when applied to enum arguments. However, the current
WP specifies that the usual arithmetic promotions are applied to the
operands of | and &, which means they are promoted to int, and there is no
standard conversion from int to an enumeral type. This situation is
probably an oversight.
Jason
Author: b91926@fsgi01.fnal.gov (David Sachs)
Date: 17 Jun 1994 11:52:02 -0500 Raw View
If you wish to handle operations on an enum type, you probably
should provide overloaded operator functions to do so. This is
a post-ARM addition to C++.
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Fri, 17 Jun 1994 19:35:00 GMT Raw View
In article <CrJ0C6.BEB@world.std.com> miket@world.std.com (Michael Trachtman) writes:
>
>I am unclear about the legality of using the |, |=, & and &=
>operators with enums. In particular, I have tried variants of
>the following program using various compilers. Each did not like
>at least one of the lines of code.
| and & can be applied to enums and cause conversions
to integral types.
|= and &= cannot be applies to enums, they require
an lvalue on the LHS of the enum type, but the form
a |= b
expands to
a = a | b
and the RHS of that is an integral type. The assignment:
enum_obj = int_obj;
is not permitted, you cant convert an integral type to an
enum type automatically (you can explicitly).
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Fri, 17 Jun 1994 19:38:21 GMT Raw View
In article <JASON.94Jun17040720@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>values of enum type when applied to enum arguments. However, the current
>WP specifies that the usual arithmetic promotions are applied to the
>operands of | and &, which means they are promoted to int, and there is no
>standard conversion from int to an enumeral type. This situation is
>probably an oversight.
Its not. Its deliberate. You cant convert an int to an enum
implicitly.
enum E {val=1} e;
e = E(1); // this is how you do it
e = 1; // error
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd, CSERVE:10236.1703
6 MacKay St ASHFIELD, Mem: SA IT/9/22,SC22/WG21
NSW 2131, AUSTRALIA