deb@svax.cs.cornell.edu (David Baraff) (03/03/89)
I'd like to make a case for stronger type checking of enum's.
In cfront 1.2, the following is legal:
--------------------
enum color { RED, GREEN, BLUE };
enum fruit { APPLE, PEAR };
color foo()
{
return PEAR; // I say this should cause a problem
}
--------------------
A 'PEAR' is of type 'fruit', and not of type 'COLOR', so
the above definition of foo should be an error (or at the
very least, a warning).
I had a function that was of type 'boolean', but accidentally
returned some other enum constant.
With strong(er) type checking the compiler could easily
have determined I had a type error.
Why shouldn't enum's have their own type, and why shouldn't
the compiler strongly type enum expressions?
David Baraff
deb@svax.cs.cornell.edu
mutchler@pitstop.UUCP (Dan Mutchler) (03/03/89)
In article <25740@cornell.UUCP> deb@cs.cornell.edu (David Baraff) writes: >I had a function that was of type 'boolean', but accidentally >returned some other enum constant. >With strong(er) type checking the compiler could easily >have determined I had a type error. > >Why shouldn't enum's have their own type, and why shouldn't >the compiler strongly type enum expressions? > I have a very similar problem with both enum's and int's. I'm trying to write some portable code that will have data written to disk. I am using overloaded functions to effect an XDR type concept. The problem is that on a PC using Zortech C++ an "int" is mapped onto a "short". If this mapping is consistent with the C++ spec then on a 32-bit machine an "int" will map onto a "long". In order to avoid a portability problem I always have to write a 32-bit integer to disk because I can't have 3 functions for dealing with integer (int, short, and long) which can then be uniquely identified. Additionally and enum type automatically maps onto one of these overloaded functions, but I'm not sure which one (I'm guessing short). The solution I have is fine and but there could be other problems I run into later where having int be a unique type from short and long would be useful. Does anyone else agree? Dan Mutchler
dld@F.GP.CS.CMU.EDU (David Detlefs) (03/04/89)
>David Baraff proposes that enums have stricter type checking. He >gives the example > >------------------------- >enum color { RED, GREEN, BLUE }; >enum fruit { APPLE, PEAR }; > >color foo() >{ > return PEAR; // I say this should cause a problem >} >------------------------- >where he would like the compiler to complain. This confuses me somewhat, as well. Having the greatest respect for Dr. Stroustrup's judgement, I'm sure there is a good reason for it, but I can't think of what it might be just sitting here. I just wanted to point out a few more potential advantages of strong type checking for enums. Note in the example above that ORANGE would be a natural member that might be added to both the "color" and "fruit" types. This is presently illegal, but if we had strong typing for enums it could be legal. The type information would eliminate ambiguity. (This could be implemented in a cfront-like translater by qualifying each enum constant with the enum name, just as is done with class members.) To further enhance the similarities between enums and classes, perhaps it would make sense to allow enum inheritance. If we had enum color { RED, YELLOW, BROWN, GREEN, BLUE }; I think it would be useful to be able to write enum low_freq_color: public color { RED, YELLOW, BROWN }; and enum high_freq_color: public color { GREEN, BLUE }; A "sub-enum", as a specialization of an enum, must contain a subset of the base enum's values. Another thing that would seem to make some conceptual sense would be to make all enums subclasses of "int" (considered as an enum). Thus, the "switch" statement needs to take an "int" -- if we write a switch that dispatches off a variable of type "int", any value is legal in a "case", but if we use a variable of an enum type in the "switch", the "cases" (except for DEFAULT:) must be drawn from the set of values in the enum. This would prevent some errors. Perhaps we could have another kind of "switch" statement, as well, that produces a compiler warning if there isn't a case for each enum value. Anyway, I realize that 1) there may be many things wrong with the above ideas, and 2) Dr. Stroustrup no doubt considered this in the course of design (it's not too different from Pascal subranges), and has a set of excellent reasons, conceptual and/or pragmatic, for not taking this kind of route, and 3) even if these are excellent ideas that he didn't think of, it would probably be impractical to add them to the language at this late date. So I don't mean this article as an attempt to change the language, but more as an exploration of what might be done in the language design space. In closing, let me point out that there are a couple of pieces of programming discipline that we could use to approach the extra safety strong enum type-checking could give us: 1) Always explicityly qualify enum member names with the name of the enum. If we write enum color { COLOR_RED, COLOR_GREEN, COLOR_BLUE }; enum fruit { FRUIT_APPLE, FRUIT_PEAR }; then we are less likely to write color foo() { return FRUIT_PEAR; // I say this should cause a problem } even though the compiler will still accept it. Also, this convention allows COLOR_ORANGE and FRUIT_ORANGE to be distinguished. Finally, if one is attempting to write a switch statement that should do something for every member of an enum, always include a DEFAULT: clause at the end that prints out at least a run-time error: enum foo { ...many members... }; switch (foo) { case FOO1: case FOO2: ... default: error("Unhandled switch value (%d) in switch in %s, line %d.\n", foo, __FILE__, __LINE__); } -- Dave Detlefs Any correlation between my employer's opinion Carnegie-Mellon CS and my own is statistical rather than causal, dld@cs.cmu.edu except in those cases where I have helped to form my employer's opinion. (Null disclaimer.) --
lpringle@bbn.com (Lewis G. Pringle) (03/04/89)
In article <25740@cornell.UUCP> deb@cs.cornell.edu (David Baraff) writes: >I'd like to make a case for stronger type checking of enum's. I agree that this would be very nice. But it does introduce some questions. Array indexing. One would probably also want to be able to declare: enum Color {r,g,b}; int a[Color]; Would you also add and Ord () function? If you can do these things, then why not also allow subranges? How about integer subranges? (Hmm... Begins to sould like Pascal?). I like the suggestion, but you can see how one might get carried away adding 'features' to the language. Lewis. "OS/2: half an operating system for half a computer." In Real Life: Lewis Gordon Pringle Jr. Electronic Mail: lpringle@labs-n.bbn.com Phone: (617) 873-4433
jas@ernie.Berkeley.EDU (Jim Shankland) (03/04/89)
In article <DLD.89Mar3120212@F.GP.CS.CMU.EDU> dld@F.GP.CS.CMU.EDU (David Detlefs) writes: >Having the greatest respect for Dr. Stroustrup's judgement, >I'm sure there is a good reason for [not having stronger type checking >of enums], but I can't think of what it might be just sitting here. I doubt it. enums were a half-baked afterthought (heh) in C; C++ probably just inherited them as is. Nobody's perfect. Jim Shankland jas@ernie.berkeley.edu
scp@raven.lanl.gov (Stephen Pope) (03/04/89)
In article <DLD.89Mar3120212@F.GP.CS.CMU.EDU> dld@F.GP.CS.CMU.EDU (David Detlefs) writes: >Having the greatest respect for Dr. Stroustrup's judgement, >I'm sure there is a good reason for [not having stronger type checking >of enums], but I can't think of what it might be just sitting here. As in C, enums aren't a *real* data type. Furthermore, cfront insists on treating char, short, int and enum as equivalent (thus there is no operator << (ostream&, char), and never a possibility of having both SomeClass::SomeClass(char) and SomeClass::SomeClass(int) constructors at the same time). This can make coding for some classes rather a drag, and at best forces one to often create little sizeof(int) classes were enums would have sufficed. (little enum Booleans with operators << and >> handling the strings "true" and "false" seem real nice, until you realize you must make them a class, and supply a base set of unary/binary operators). G++ is at least willing to recognize the differences amongst all these types, but alas the *standard* coersion rules will always silently convert one enum type into another enum type, ala C. Making them distinct, without standard coersions, would make many other things rather difficult and even ugly. Stephen Pope scp@santafe.edu
scs@vax3.iti.org (Steve Simmons) (03/09/89)
In article <36748@bbn.COM> lpringle@labs-n.bbn.com (Lewis G. Pringle) writes: >In article <25740@cornell.UUCP> deb@cs.cornell.edu (David Baraff) writes: >>I'd like to make a case for stronger type checking of enum's. > >I agree that this would be very nice. But it does introduce some >questions. Array indexing. > >One would probably also want to be able to declare: > enum Color {r,g,b}; > int a[Color]; >[[and goes on to talk about ord() and Pascal]] Enums as presently constructed give one a false sense of security. Aside from such wonderful questions as strong type checking, we have to deal with stupid issues like enum Color { red, green, blue, orange } ; vs. enum Fruit { plum, orange, avocado, kumquat } ; The intent of enum seems to be a primitive user-defined class -- a named type with a list of specific values which it may take. Let's keep enum in it's present form but just tighten up the checking. It looks like a prime case where C++ can improve C without breaking.