[comp.lang.c++] stronger type checking of enums

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.