[net.lang.c] more why I dont like C enums

swatt (11/06/82)

I confess I never had the patience to find all the problems with
C enumerated types that Mark Horton detailed.  My use of enums
is limited to:

	typedef enum { NO, YES } BOOL;

Now while this lets me do:

	BOOL flag = YES;

	if (flag) ...

It doesn't let me do:

	BOOL
	iseof () {
		int n = 0;

/*###26 [cc] warning: enumeration type clash, operator RETURN %%%*/
		return (n == 0);
	}


You have to:

		return ((BOOL) n == 0);

However, for such limited use it is at least clearer in the source
what is going on, and you can always replace the enum typedef with
a typedef for (int) and the appropriate #define's instead.

While we're on the subject, I also have zero use for the 'void' type
in C.  I never could figure out why it was needed in the first place.
I just use:

	typedef int VOID;
	# ifdef lint
	 VOID __void__;
	# define IGNORE (X)	__void__ = (VOID) (X);
	#else
	# define IGNORE (X)	X
	#endif

and then in the code:

	IGNORE (fclose (stream));

It does the job to keep lint happy, and declares in the source that
you at least think you know what you're doing.  It also works on
any C compiler I've used recently.  The only problem I've encountered
is one preprocessor wouldn't let you continue a macro on another line,
so if you try to keep everything to 80 columns:

	< many nested loops and conditionals ...>

						IGNORE (function (with,
							lots_of, args,
							that, wont_fit,
							ona_line));

it barfs, but it seems to me that qualifies as a genuine preprocessor
bug and shouldn't constrain one in the general case.

The problem with the true 'void' type (at least on 4.1bsd) is:

	void func () { ; }
	int ifunc () { ; }

	test  () {
		void (*funcp)();
		int (*ifuncp)();
/*###67 [cc] void type for ugottabekiding %%%*/
/*###67 [cc] unknown size %%%*/
		void ugottabekiding;
		
/*###69 [cc] operands of = have incompatible types %%%*/
		funcp = func;
/*###70 [cc] operands of = have incompatible types %%%*/
		ifuncp = func;
/*###71 [cc] warning: illegal pointer combination %%%*/
		funcp = ifunc;
/*###72 [cc] ugottabekiding undefined %%%*/
	}

Now it seems reasonable to disallow the 'void' type to declare
identifiers ("ugottabekidding"), but the whole point of it is to
properly declare functions which don't return values.  Note that the
declaration "void (*funcp)();" is legal -- so how come I can't use it?
Anyway you try you lose: you can't use the name "func" for anything --
it's a hard error.  If you try to use "ifunc" instead it draws a
warning.

Just to balance this gripe a bit, the other change that went into C
with 'enum' was structure and union assignment, which is a big win,
especially for yacc parsers.  Another more recent change is the rule
that each structure type gets its own symbol table so:

	struct FOO {
		struct FOO *next;
		int bar;
	};

	struct BAR {
		int foo;
		struct BAR *next;
		int notinfoo;
	};

no longer gives you the "next: multiply defined" error.  This
considerably reduces the imagination required to keep all the
structure members uniquely named in a large system.  This also
has the by-product of enforcing stricter member usage:

	struct FOO *foop;

	foop->notinfoo = 0;

is now illegal.

	- Alan S. Watt

mem (11/07/82)

c
You are authorized to consider this comment to be picky.

The use of

  enum  BOOL { YES, NO };

may not work right; but to my mind (wherever that is), this usage
of enum isn't reasonable anyway, because it states that not only
do you know what values enum generates for its members (maybe
valid, maybe not, depending on your outlook... mine is to consider
enum members as valueless), but that you have to know what
values the compiler assumes for truth and falseness (also, maybe
valid, maybe not; at some point you have to know this, it is
mainly the matching of these two assumptions that makes this
one bad, again to my mind).  Granted, at some point you can't
get around knowing what the values for true and false are.
But I'd rather see them in #defines where you explicitly state
that you know what they are than declaring them to be
enumerated types.

Picky, picky.

Mark Mallett

mem (11/07/82)

c
Please forgive the statement error in the previous article (the
declaration of the type BOOL).  If you didn't notice, never mind.
If you noticed and forgave, thank you.

MM