[comp.lang.c] enum - enum ?

merlyn@starfire.UUCP (06/03/87)

What does the current standard say about enum - enum (both same enum type)?
I have tried this with 2 compilers; one complained about using enums in
an expression (needs cast to int), the other one didn't.

I think it would be reasonable for enum - enum to be an integer value,
just as ptr - ptr is, and for similar reasons; you want the 'distance'
between them.  This would also imply  enum + int  == enum  and  enum++ is ok

Of course, if you do:   enum color {red=99, blue=-4, green=200};
then green-red will be 101, not 2, and red++ != blue, but that's your doing.

I know (int) green - (int) red will always work, but it's ugly.
If enums are too strongly typed (what is this, Pascal?) people will
go back to lists of #defines.

-----
"Oh carrots!  Oh crumbs!"
Merlyn Leroy
	...rutgers!dayton!rosevax!rose3!starfire!merlyn

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/05/87)

In article <139@starfire.UUCP> merlyn@starfire.UUCP (Brian Westley) writes:
>What does the current standard say about enum - enum (both same enum type)?

As I recall, enums are now officially ints in disguise.

karl@haddock.UUCP (06/06/87)

In article <139@starfire.UUCP> merlyn@starfire.UUCP (Brian Westley) writes:
>What does the current standard say about enum - enum (both same enum type)?

It says that enums are just ints.

Personally, I think I'd be happy to have both enums and chars behave like
pointers arithmetically (e.g.  char+int == char, enum-enum == int, other
combinations illegal), provided there's also a type "byte" ("short short"?)
for arithmetic usage.

>I know (int) green - (int) red will always work, but it's ugly.
>If enums are too strongly typed (what is this, Pascal?) people will
>go back to lists of #defines.

But if enums are too weakly typed, what's their advantage over ints?

I tend to use enums only when they would be legal in the strictest compilers,
i.e. when the actual values are completely arbitrary.  Given the suggested
"pointer-like" semantics for arithmetic, and the ability to declare an array
indexed by enums (or other types!), I could find more use for them.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
int hue[enum color] = { RED: 0x00F, GREEN: 0x0F0, BLUE: 0xF00 }; /* I wish */

guy@gorodish.UUCP (06/06/87)

> Personally, I think I'd be happy to have both enums and chars behave like
> pointers arithmetically (e.g.  char+int == char, enum-enum == int, other
> combinations illegal), provided there's also a type "byte" ("short short"?)
> for arithmetic usage.

I tend to agree (I would prefer "short short" as the adverb here),
having learned that Type Systems Are Your Friend and that, in most
cases, there is no benefit to be gained from promiscuously flouting
the rules of the type system (and significant benefit to be gained by
following those rules - just running "lint" on code, including
kernels, before building and testing them has often turned up
errors).

> But if enums are too weakly typed, what's their advantage over ints?

I hope certain legal but dubious uses of "enum"s will at least generate
warnings even from X3J11-conforming compilers; for example, coercing
something of type "enum foo" to something of type "enum bar".  This
might not be as good at catching errors as forbidding those uses, but
at least it means that the use wouldn't pass without comment.

> Given the suggested "pointer-like" semantics for arithmetic, and the
> ability to declare an array indexed by enums (or other types!), I could
> find more use for them.
> int hue[enum color] = { RED: 0x00F, GREEN: 0x0F0, BLUE: 0xF00 }; /* I wish */

I agree that it would be nice to support declaring arrays indexed by
"enum"s.  (What "other types" would be indices?  "char", presumably;
the only other types I could see would be subrange types - are you
proposing adding them to C?)  It fits the model of an array as a
function from the set of all values of the index type to all values
of the base type, although to properly implement that model subrange
types would be needed (an array indexed by "int", in this model,
would have the set of all values of type "int" as its domain, which
implies a VERY big array).

One interesting possibility is suggested by the fact that the set of
numerical encodings of "enum" values need not be "dense", and thus
that

	enum cookie { chocolate_chip = 1, oreo = 10, oatmeal = 100 };
	int price[enum cookie];

might cause "price" to be a sparse array, with lookups in that array
done by some technique other than indexing.  This is analogous to
"switch" statements; the compiler selects different implementations
based on the set of values used, with indexing used for a
sufficiently "dense" set, various combinations of hashing and
table-search used for less-"dense" sets, and a cascade of comparisons
used for other sets.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

mar@hpclla.UUCP (06/09/87)

>I think it would be reasonable for enum - enum to be an integer value,
>just as ptr - ptr is, and for similar reasons; you want the 'distance'
>between them.  This would also imply  enum + int  == enum  and  enum++ is ok

The following statements assume the declaration: 
			enum color {red=1, blue=4, green=5};
			enum fruit {apple=1, orange=4, grape=5};

for clarification: color is an enum; red is an enum constant;

What is the use of an expression such as red++  ??

Enum constants are integer constants - why would you want to allow the 
modification of a constant (ie: red++) - might as well use ints.

I agree that enums in general should be implemented as a special case of
integers - allowed wherever integer constants are allowed, but with extra
restrictions regarding assignment of two different enums (color = fruit)
and addition of enums or enum constants.

Subtracting two enum constants or adding a integer to an enum constant could 
be useful, but what would you use the addition of two enum constants for?

Should enum_constant - enum_constant only be allowed if both enum constants
are elements of the same enum type?

I would like to have enums and enum constants be flexible, but I also would
like the extra type-checking for enums; otherwise I might as well use
#define's for compile-time constants.
type.

karl@haddock.UUCP (Karl Heuer) (06/09/87)

In article <20540@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes:
>[haddock!karl (Karl Heuer) writes:]
>>But if enums are too weakly typed, what's their advantage over ints?
>
>I hope certain legal but dubious uses of "enum"s will at least generate
>warnings even from X3J11-conforming compilers; for example, coercing
>something of type "enum foo" to something of type "enum bar".  This
>might not be as good at catching errors as forbidding those uses, but
>at least it means that the use wouldn't pass without comment.

Perhaps you're right; the May86 dpANS lists under Common Warnings: "A value is
given to an object of an enumeration type other than by assignment of an
enumeration constant that is a member of that type."  (Which seems unusually
strict, as it would produce a warning for some perfectly valid code written
under the "strong enum" model.)  If this or similar wording appears in the
final Draft, I expect people will continue to use enum as they do now.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

msb@sq.UUCP (06/09/87)

Karl Heuer (karl@haddock.ISC.COM.UUCP), replying to another article, writes:
> [The current draft standard] says that enums are just ints.

More precisely, their values promote to int, the same way that chars do.

> >If enums are too strongly typed (what is this, Pascal?) people will
> >go back to lists of #defines.
> 
> But if enums are too weakly typed, what's their advantage over ints?

Perhaps Karl hasn't ever had to maintain a program that uses a "list of
#defines" over 90 elements long, with the #define for the length of the
list in a different place from the list itself.  *I* have.  If the original
coder hadn't been defensive and made the length #define a bit longer
than the actual list then was, things could have gotten verrrrry awkward...

Mark Brader, SoftQuad Inc., Toronto, utzoo!sq!msb
#define	MSB(type)	(~(((unsigned type)-1)>>1))

edw@ius2.cs.cmu.edu (Eddie Wyatt) (06/10/87)

In article <4400002@hpclla.HP.COM>, mar@hpclla.HP.COM (Michelle Ruscetta) writes:
> 
> >I think it would be reasonable for enum - enum to be an integer value,
> >just as ptr - ptr is, and for similar reasons; you want the 'distance'
> >between them.  This would also imply  enum + int  == enum  and  enum++ is ok
> 
> The following statements assume the declaration: 
> 			enum color {red=1, blue=4, green=5};
> 			enum fruit {apple=1, orange=4, grape=5};
> 
> for clarification: color is an enum; red is an enum constant;
> 
> What is the use of an expression such as red++  ??
					   ^^^

	I think you mean a variable of type color.

   color rgb;

   rgb++ - could be used as the successor function
   rgb-- - cound be used as the predessor

  I just tried this with my C complier and it didn't allow an enum
variable in the increment statement.   I guess they wanted to avoid
the semantic issues here.  Example

	rgb = red;
	rgb++;
	does rgb == blue or red+1?


> 
> Enum constants are integer constants - why would you want to allow the 
> modification of a constant (ie: red++) - might as well use ints.

	No one should or can modify a constant in C. Again I think you
	mean a enum variable.
> 
> I agree that enums in general should be implemented as a special case of
> integers - allowed wherever integer constants are allowed, but with extra
> restrictions regarding assignment of two different enums (color = fruit)
> and addition of enums or enum constants.
> 
> Subtracting two enum constants or adding a integer to an enum constant could 
> be useful, but what would you use the addition of two enum constants for?

	type enum {offset1 = 3, offset2 = 5, offset3 = 6} offsettype;
	type enum {index1 = 4, index2 = 9, index3 = 9} index;

	int where = offset1*sizeof(mytype) + index2; 
			/* array indexing function ^ */
	
> 
> Should enum_constant - enum_constant only be allowed if both enum constants
> are elements of the same enum type?
> 
> I would like to have enums and enum constants be flexible, but I also would
> like the extra type-checking for enums; otherwise I might as well use
> #define's for compile-time constants.
> type.


  I view C enumerations a as facility for defining set of interrelated
constants. I use them for program readability, not for any extra
semantic meaning that is attached.  I find

	typedef enum {PEUTOKEN, PEUFRAME, PEUFFRAME ...} PARSEERRORTYPE;

 A lot more meaningful than 

	#define PEUTOKEN 	0
	#define PEUFRAME 	1
	#define PEUFFRAME 	2
	.....

-- 
					Eddie Wyatt

e-mail: edw@ius2.cs.cmu.edu

karl@haddock.UUCP (Karl Heuer) (06/12/87)

In article <1191@ius2.cs.cmu.edu> edw@ius2.cs.cmu.edu (Eddie Wyatt) writes:
>I just tried [using "++" and "--" for successor and predecessor] with my C
>complier and it didn't allow an enum variable in the increment statement.  I
>guess they wanted to avoid the semantic issues here.  Example [given the
>declaration: enum color {red=1, blue=4, green=5};]
>    rgb = red;  rgb++;
>does rgb == blue or red+1?

Clearly it should be red+1, which should have the value (enum color)2.
However, since this value is not a declared member of the set, one could argue
that the result is undefined.

>[mar@hpclla.HP.COM (Michelle Ruscetta) writes:]
>>I would like to have enums and enum constants be flexible, but I also would
>>like the extra type-checking for enums; otherwise I might as well use
>>#define's for compile-time constants.
>
>I view C enumerations a as facility for defining set of interrelated
>constants.  I use them for program readability, not for any extra
>semantic meaning that is attached.

Yes, it does add to readability, but I believe in typechecking too.  I use
"enum" even though "int" will do the same job and more, for the same reason I
use "while" instead of "goto": I've observed that programs that can get away
with the weaker construct are more likely to be correct.  In my programs,
using an uncasted enum in an int context is a bug; naturally I prefer the
compiler (either cc or lint) to warn me.

In fact, while I acknowledge that "typedef creates a new name for a type, not
a new type; it does not imply dimensional analysis" (paraphrased from K&R),
I'd like to have a feature that *does* produce a new type.  (Though I'm not
yet sure what operators should be allowed on such a new type.)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

am@cl.cam.ac.uk (Alan Mycroft) (06/12/87)

In article <5959@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>As I recall, enums are now officially ints in disguise.

Hmm.  Checking in the draft (p54 para at line 40) seems to agree with this,
but lets consider:
   enum joke { a=0, b=999999999 };
what happens if 'int' is only 16 bits?  Does 'b == 999999999 & 0xffff'?
Similarly, consider
   enum { a = ~0U }
on a 32 bit two's complement machine.  What is 'a/2'? is it -1/2 (probably 0)
or 0x7fffffff?

Consider sizeof too: "The implementation many use the set of values ...
to allocate ... storage".
What does this mean for:
   enum query { zero=0, one=1 } q;
The spec. says zero is int hence
   sizeof(zero) = sizeof(int).
On the other hand sizeof(q) maay be sizeof(char).
Is this reasonable?
What about sizeof(q)?

jfjr@mitre-bedford.arpa (06/18/87)

 One of the things I like about Pascal (Yes I *definitely* do like
Pascal) is its handling of enumerated scalar types (and subranges thereof)
I could find true happiness and fulfilment if C would handle
enums the same way - right now the approach seems to be muddled
and schizophrenic. Imagine, with the power C has to be able to
increase its readiblity (which it hasn't) by allowing TRUE array
indexing with enums( 'twould be paradise enow)

                                    Jerry Freedman,Jr
                                    jfjr@mitre-bedford.arpa

edw@ius2.cs.cmu.edu (Eddie Wyatt) (06/19/87)

In article <7906@brl-adm.ARPA>, jfjr@mitre-bedford.arpa writes:
> 
>  One of the things I like about Pascal (Yes I *definitely* do like
> Pascal) is its handling of enumerated scalar types (and subranges thereof)
> I could find true happiness and fulfilment if C would handle
> enums the same way - right now the approach seems to be muddled
> and schizophrenic. Imagine, with the power C has to be able to
> increase its readiblity (which it hasn't) by allowing TRUE array
> indexing with enums( 'twould be paradise enow)
> 
>                                     Jerry Freedman,Jr
>                                     jfjr@mitre-bedford.arpa


   You've touched two bad notes with me here:  One calling Pascal a usable
language and, two saying C code in general is not readable.

  Lets talk about Pascal.

  Let me see you write a single function to do a sumation over an array of
of integers of arbitrary size.  Can't do it huh. The problem, Pascal
doesn't suppose "generic" array sizes.

  Case statements in Pascal are a total failure. Since there is no
default clause, one has to test whether the switch variable
is in the case statement's range or is outside the range. You might
as well use if-then-elses.

  There are loop holes in Pascals suppositely "can't screw yourself over"
attitude too.   One in the function as a parameter to function 
construct, there's no way of specifying the arguements to the input
function.  Hence one could do something like declare a function that takes 2
arguements. Pass that function to another function as an arguement and
call the input function with 3 arguements when it was declared to take
only two.  

   The other loop hole that I can think of is the use of case variant
records to access data that is in one form say int as another say
float.

   Another flop is the conditional expressions.  Pascal does not do
short-circuit evaluation of conditional expressions.  This
posses at least two problems, the obvious one being less efficient code.
The other being the awkward constructs that one must use to 
achieve the equivalent of short-circuit evaluation.  The old

	if (not (p = nil)) then
		if (p^.field = x) then .....

You  call that more readable then this!

	if (p && p->field == x) ...

  And how about "despose".  Dynamic memory allocation is in the Pascal
definition.  I would like to see one implementation of "despose" that
did something reasonably.  Clearing the heap up until the pointer
that you are freeing is not reasonable!

  Other little things to squawk about
	o no bit-wise operations
	o no separate compulation
	o no utilities like most C implementations
	  (refering to stdio.h, varargs.h ....)

  Now for the issue of readability in C.  This really is more of an issue
of the PROGRAMMER'S ABLITY to write readable code, not the languages
syntax or semantics! At least in the case of C vs Pascal.

-- 
					Eddie Wyatt

e-mail: edw@ius2.cs.cmu.edu

terrorist, cryptography, DES, drugs, cipher, secret, decode, NSA, CIA, NRO.

edw@ius2.cs.cmu.edu (Eddie Wyatt) (06/19/87)

  Example of the pathological case for enums array indexes.  (An implementors
perspective)


	typedef enum	{W = -10, X = -100, Y = 10, P = 0, Z = 0} PATHO ;


	int sumation(x)
    	    int x[PATHO];
    	    {
    	    register PATH i;
    	    register int sum;
	
    	    for (i = W; i <= Z; i = successor(i))
		    sum += x[i];

    	    return(sum);
    	    }

  The task here is to sum the over the first 5 indexes of  array x.

  Lets consider the code that needs to be generated for the statements:

    		for (i = W; i <= Z; i = successor(i))
	    	    sum += x[i];

    	first try

		for (i = -10, i <= 0; i = enum_get_next(i))
	    	    sum += *(x + lookup_hashtable(i));

	execute the loop and we get :

		i = -10, -100, 10 - exit loop.

  	Nope that can't be right.


  Assume we can fix the above problem somehow and lets consider the code
generated for, lets say:

		sum += x[P];

	try

		sum += *(x + lookup_hashtable(0));

	Hmmm does lookup_hashtable return 3 or 4???


   Lets consider an alternate solution enums as array indexes.  Allow each
enumeration element  have two values associated with it - the place it
holds in the enumeration (for W that would be the value 0) and the
assigned value (for W that would be the value -10).

  From the context, one MIGHT be able to determine which is the correct
value to use.  In the above case.


	for (i = W; i <= Z; i = successor(i))
	    	    sum += x[i];

yields :

	for (i = 0; i <= 4; i++)
		sum += *(x+i);

    The above context prescribes that W,Z and i be intepreted as "place"
values, not the "assigned" values.  Look here too, no hashing function
either - efficient code.

   The major question here is whether the correct interpretation can
always be choosen given the context the variable is being used in. 


Example :

	typdef enum {RED = 30, GREEN = 40, BLUE = 50} COLORTABLE;
	......
	colortable[RED] = 64;
	.....

Are we indexing colortable[0] or colortable[30]??

We might say that if colortable is defined as

	int colortable[COLORTABLE] then the actual index is 0.

If colortable is defined as

	int colartable[] or colortable[256] 

then we are refering to index 30.

  There are more things to be thought out, but this is a posible
implementation alternative for enums in C.


-- 
					Eddie Wyatt

e-mail: edw@ius2.cs.cmu.edu

terrorist, cryptography, DES, drugs, cipher, secret, decode, NSA, CIA, NRO.

mouse@mcgill-vision.UUCP (der Mouse) (06/23/87)

In article <525@haddock.UUCP>, karl@haddock.UUCP (Karl Heuer) writes:
> [quotes stuff about enums]

> Perhaps you're right; the May86 dpANS lists under Common Warnings: "A
> value is given to an object of an enumeration type other than by
> assignment of an enumeration constant that is a member of that type."

For example,

enum foo { RED, GREEN, BLUE };
enum foo x;
enum foo y;
...
 x = RED;  /* this is OK */
 y = x;	   /* but this generates a Common Warning; x is not constant */

Good heavens.

> (Which seems unusually strict, as it would produce a warning for some
> perfectly valid code written under the "strong enum" model.)

I certainly see what you mean.  I hope they come to their senses.

					der Mouse

				(mouse@mcgill-vision.uucp)

karl@haddock.UUCP (Karl Heuer) (06/26/87)

In article <818@mcgill-vision.UUCP> mcgill-vision!mouse (der Mouse) writes:
>In article <525@haddock.UUCP>, karl@haddock.UUCP (Karl Heuer) writes:
>> Perhaps you're right; the May86 dpANS lists under Common Warnings: "A
>> value is given to an object of an enumeration type other than by
>> assignment of an enumeration constant that is a member of that type."
>
>For example, [ x=RED is OK, but y=x is not ].  Good heavens.
>
>> (Which seems unusually strict, as it would produce a warning for some
>> perfectly valid code written under the "strong enum" model.)
>
>I certainly see what you mean.  I hope they come to their senses.

The Oct86 dpANS (which I did not have at hand when I posted earlier) has
changed this to "constant or variable".  Better, but I'm still not sure
whether this is sufficient -- It still seems to allow a warning for x=y[i] or
x=z().  (But "i=x", which is equally illegal under the strong model, is not
listed as a Common Warning.  Hmm.)

Of course, A.5 is not part of the Standard itself, and so should not be
considered binding.  In practice, I expect the compiler-writers will use
common sense in this regard.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint