[comp.lang.c] Enumerated types... what's the point?

dks@shumv1.uucp (D. K. Smith) (03/22/90)

I thought... How nice!  These enumaerated types allow me "type check"
myself when I am using them for distinguishing between different
variable types that possess similar data structures.

For example:

typedef enum {
	subjPoly=0,
	clipPoly
} PolyKind;
	 
	  
typedef enum {
	insidePoly=0,
	outsidePoly
} DisplayKind;


However, to my surprise, I discovered that I could interchange these
critters among themselves as well as with Booleans!  Is this what is
supposed to happen?  I have not RTFM'd the C scriptures but my 
immediate reaction is "what's the point!...I could just as easily
used #define and accomplished the same thing.  

I guess I am supposed to conclude that an int is an int is an int... no
matter what kind of label you put on it?!?


dk smith
------------------------------------------------------------------------
dks@shumv1.ncsu.edu                |                ude.uscn.1vmuhs@skd
-my opinions reflect my opinions.  |  .snoinipo ym tcelfer snoinipo ym-
------------------------------------------------------------------------

henry@utzoo.uucp (Henry Spencer) (03/23/90)

In article <1990Mar22.053148.10351@ncsuvx.ncsu.edu> dks@shumv1.ncsu.edu (D. K. Smith) writes:
>... I have not RTFM'd the C scriptures but my 
>immediate reaction is "what's the point!...I could just as easily
>used #define and accomplished the same thing.  

Enumerated types were basically a kludge.  X3J11 seriously debated leaving
them out entirely.  Arguments about not breaking existing code, etc, led
to them being left in, but as a flavor of integer rather than as real live
independent types.  That's all they ever were in C.
-- 
US space station:  8 years    |     Henry Spencer at U of Toronto Zoology
and still no hardware built.  | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

dave@cs.arizona.edu (David P. Schaumann) (03/23/90)

In article <1990Mar22.053148.10351@ncsuvx.ncsu.edu>, dks@shumv1.uucp (D. K. Smith) writes:
| 
| I thought... How nice!  These enumaerated types allow me "type check"
| myself when I am using them for distinguishing between different
| variable types that possess similar data structures.
| 
| [ example deleted ]
| 
| However, to my surprise, I discovered that I could interchange these
| critters among themselves as well as with Booleans!  Is this what is
| supposed to happen?  I have not RTFM'd the C scriptures but my 
| immediate reaction is "what's the point!...I could just as easily
| used #define and accomplished the same thing.  
| 
| I guess I am supposed to conclude that an int is an int is an int... no
| matter what kind of label you put on it?!?

The point of enums is that they offer more flexability than using #define.
For example, say you had a list of 100 symbols you wanted to use as constants.
Of course, order is important.  So, you type out 100 #defines.  Ok, fine.
Suddenly, you discover you need a new symbol, which should go between the
third and forth symbols.  If you use defines, you are pretty much stuck
retyping the values on 97 defines.  If you use enum, all you have to do
is insert the name in the list, and continue on your merry way.
Also, if you use #defines, you may be tempted by your explicit knowledge of
the value of that symbol to use it in some way that would break if you
change the value.
| 
| 
| dk smith
| ------------------------------------------------------------------------
| dks@shumv1.ncsu.edu                |                ude.uscn.1vmuhs@skd
| -my opinions reflect my opinions.  |  .snoinipo ym tcelfer snoinipo ym-
| ------------------------------------------------------------------------


--------------------------------------------------------------------------
Dave Schaumann		| These are my opinions.
dave@cs.arizona.edu	| 
--------------------------------------------------------------------------

buck@granite.cr.bull.com (Ken Buck) (03/23/90)

Another point of 'enum' types is visibility.  Use of #define results in a
definition with file scope, while an enum type definition can have the same
scope as any other object (i.e., can be defined within a function or block).

flc@n.sp.cs.cmu.edu (Fred Christianson) (03/24/90)

In article <159@caslon.cs.arizona.edu> dave@cs.arizona.edu (David P. Schaumann) writes:
>For example, say you had a list of 100 symbols you wanted to use as constants.
>Of course, order is important.  So, you type out 100 #defines.  Ok, fine.
>Suddenly, you discover you need a new symbol, which should go between the
>third and forth symbols.  If you use defines, you are pretty much stuck
>retyping the values on 97 defines.  If you use enum, all you have to do
>is insert the name in the list, and continue on your merry way.

#define a1	1
#define a2	a1 + 1
#define a3	a2 + 1
...
#define a100	a99 + 1

would allow you to easily add a new symbol anywhere.

#define a1	1
#define a2	a1 + 1
#define new     a2 + 1
#define a3	new + 1
...
#define a100	a99 + 1

I think this would be better done with enums simple because I prefer the
way the enum definition looks to the way 100 #defines look.  But if
order is important the #defines may be better because you are immediately
aware of the order by looking at the #defines whereas you (or at least me)
don't tend to think of enum symbols as ordered.

>Also, if you use #defines, you may be tempted by your explicit knowledge of
>the value of that symbol to use it in some way that would break if you
>change the value.

I've seen this done with enums also, although it is less likely to happen.

----
Fred

jamison@hobbes.Sun.COM (Jamison Gray) (03/24/90)

>In article <1990Mar22.053148.10351@ncsuvx.ncsu.edu>, dks@shumv1.uucp (D. K. Smith) writes:
>| However, to my surprise, I discovered that I could interchange these
>| critters among themselves as well as with Booleans!  Is this what is
>| supposed to happen?  I have not RTFM'd the C scriptures but my 
>| immediate reaction is "what's the point!...I could just as easily
>| used #define and accomplished the same thing.  

Another advantage enumerated types have over #define'ed constants
is that they're handled by the compiler, rather than cpp.
As a result, a debugging compiler (and thus a debugger) can know 
about the names associated with a value.  

In the dbx debugger on a Sun, for instance, printing out the
value of a variable with an enumerated type gives you the symbolic
name, which is generally a whole lot more helpful than the 
integer value.  For example, the Phigs Ptxalign type is a structure
of two enumerated types.  Here's what I get when I print one out:

(dbxtool) print ptxalign
ptxalign = {
        hor = PAH_LEFT
        ver = PAV_HALF
}
			-- Jamie Gray
Jamie Gray, Sun Microsystems    "Broken pipes; broken tools;
Mountain View, CA                People bendin' broken rules"
Internet:  jamison@Sun.COM            - Bob Dylan, "Everything's Broken"

wallis@labc.dec.com (Barry L. Wallis) (03/24/90)

In article <8578@pt.cs.cmu.edu>, flc@n.sp.cs.cmu.edu (Fred Christianson) writes...
[ intervening text deleted ]
> 
>But if
>order is important the #defines may be better because you are immediately
>aware of the order by looking at the #defines whereas you (or at least me)
>don't tend to think of enum symbols as ordered.
> 
[ intervening text deleted ]
>----
>Fred

Is ordering defined on type enum? I have a book on Turbo-C (can't remember the
title but it's published by Howard Sams) which says that ordering on the
elements of an enum is undefined. For example, enum { JAN, FEB, MAR } months
would make the comparison (FEB > JAN) illegal! I don't believe this is reality
in Turbo-C, but, I'm currently 1700 miles from my PC and library. 
---
Barry L. Wallis			USENET: wallis@labc.dec.com
Database Consultant		Prodigy (don't laugh): DNMX41A
U.S. DECtp Resource Center	DECUServe: EISNER::WALLIS (not on the net yet)
Los Angeles, CA			"No one voted for me, I represent myself"
---

raymond@ragu.berkeley.edu (Raymond Chen) (03/24/90)

Fred Christianson (flc@n.sp.cs.cmu.edu) proposed:
>#define a1	1
>#define a2	a1 + 1
>#define a3	a2 + 1
>...
>#define a100	a99 + 1

(Noting of course that we really should be parenthesizing the right-hand-sides.)

I wrote code like this back when I worried about porting to compilers
that didn't support enums.  It has the severe drawback that adding a
new symbol between two other symbols requires you to modify the line AFTER
the one you're inserting.

>#define a1	1
>#define a2	a1 + 1
>#define new     a2 + 1
>#define a3	new + 1		<--- see?
>...
>#define a100	a99 + 1

And it is a pain in the *** always having to go and modify lines that
ostensibly have nothing to do with what you're REALLY doing.  Especially
when the symbol you've added has a long name like COUNTERCLOCKWISE_ORIENTED,
so you have to type it twice and hope you don't misspell it the second time.
(And I assure you that forgetting to modify that subsequent line will
create bugs so absurdly subtle you'll wish you were bald.)

The enum method also makes the names of the symbols available to your debugger.

x(s)char*s;{*s&&(x(s+1),putchar(*s));}main(){x("\ndlrow ,olleh");}

(Oops, sorry, wrong newsgroup.)
--
raymond@math.berkeley.edu     Maintainer of the csip Frequently Asked Questions

sullivan@aqdata.uucp (Michael T. Sullivan) (03/24/90)

I missed the beginning of this discussion so forgive me if this has
been gone over but has anybody mentioned the assignment of clashing
enum variables?  For instance:

typedef enum { red, green, brown, yellow } colors;
typedef enum { huey, dewey, louie } ducks;

main()
{
colors	a;
ducks	b;

	a = red;
	b = huey;
	a = 1
	a = b;
}

produces a compiler error at "a = 1" and "a = b".  This makes sure people 
can't make an end run around the values a given variable should have,
which they could easily do if #define's were used for the values.
-- 
Michael Sullivan          uunet!jarthur!aqdata!sullivan
aQdata, Inc.              sullivan@aqdata.uucp
San Dimas, CA             +1 714 599 9992

cjc@ulysses.att.com (Chris Calabrese) (03/24/90)

In article <1480@mountn.dec.com>, wallis@labc.dec.com (Barry L. Wallis) writes:
| Is ordering defined on type enum? I have a book on Turbo-C (can't remember the
| title but it's published by Howard Sams) which says that ordering on the
| elements of an enum is undefined. For example, enum { JAN, FEB, MAR } months
| would make the comparison (FEB > JAN) illegal! I don't believe this is reality
| in Turbo-C, but, I'm currently 1700 miles from my PC and library. 

| Barry L. Wallis			USENET: wallis@labc.dec.com
| Database Consultant		Prodigy (don't laugh): DNMX41A
| U.S. DECtp Resource Center	DECUServe: EISNER::WALLIS (not on the net yet)
| Los Angeles, CA			"No one voted for me, I represent myself"

If I remember correctly, ANSI says that the enums are to be stored as
ints and that they are ordered from 0 to n, unless the programmer
states otherwise (I think the syntax is enum {bar=5, foo, bugger ...).

Don't remember if (FEB > JAN) works, but ((int)FEB > (int)JAN)
definitely works.
-- 
Name:			Christopher J. Calabrese
Brain loaned to:	AT&T Bell Laboratories, Murray Hill, NJ
att!ulysses!cjc		cjc@ulysses.att.com
Obligatory Quote:	``Anyone who would tell you that would also try and sell you the Brooklyn Bridge.''

6sigma2@polari.UUCP (Brian Matthews) (03/24/90)

In article <1990Mar22.164943.10459@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
|Enumerated types were basically a kludge.  X3J11 seriously debated leaving
|them out entirely.  Arguments about not breaking existing code, etc, led
|to them being left in, but as a flavor of integer rather than as real live
|independent types.  That's all they ever were in C.

For some C compilers, your last sentence isn't true.  pcc2's enums weren't
interchangable with integers, although they weren't full separate types with
separate name spaces and such either.  ANSI enums, on the other hand, are
little more than fancy #defines (although you can: a - insert new ones in the
middle without renumbering the others by hand and b - have the compiler tell
you how many there are.)
-- 
Brian L. Matthews	blm@6sceng.UUCP

dks@shumv1.uucp (D. K. Smith) (03/24/90)

In article <1990Mar23.234509.21638@aqdata.uucp> sullivan@aqdata.uucp (Michael T. Sullivan) writes:
>I missed the beginning of this discussion so forgive me if this has
>been gone over but has anybody mentioned the assignment of clashing
>enum variables?  For instance:
>

THIS!  is exactly the reason I posted the original article titled
"...what's the point",  'cuz I thought I was really getting some 
mileage out of this *type*ing in the the language.  I put this code to 
my compiler (THINK C 3.02).... the results were expected.  It took it
without a htich.  I am new to C, however I still have an opinion.  The
"typing" going on here is an illusion at best in my compiler.  Did you
try this in your compiler?  I do understand the positions of the C-gods
when decreeing the new standard to make as few apps break as possible.
But I still don't agree with it. 

I think if this was implemented in the way that is intuitive to me it
would be a very powerful tool.  Oh well...

>typedef enum { red, green, brown, yellow } colors;
>typedef enum { huey, dewey, louie } ducks;
>
>main()
>{
>colors	a;
>ducks	b;
>
>	a = red;
>	b = huey;
>	a = 1
>	a = b;
>}
>
>produces a compiler error at "a = 1" and "a = b".  This makes sure people 
>can't make an end run around the values a given variable should have,
>which they could easily do if #define's were used for the values.

Yeah right... I wish it was so in my compiler...  :-)

>-- 
>Michael Sullivan          uunet!jarthur!aqdata!sullivan
>aQdata, Inc.              sullivan@aqdata.uucp
>San Dimas, CA             +1 714 599 9992


dk smith

dave@cs.arizona.edu (David P. Schaumann) (03/24/90)

In article <1480@mountn.dec.com>, wallis@labc.dec.com (Barry L. Wallis) writes:
> 
> 
> Is ordering defined on type enum? I have a book on Turbo-C (can't remember the
> title but it's published by Howard Sams) which says that ordering on the
> elements of an enum is undefined. For example, enum { JAN, FEB, MAR } months
> would make the comparison (FEB > JAN) illegal! I don't believe this is reality
> in Turbo-C, but, I'm currently 1700 miles from my PC and library. 
> ---

From _The_C_Programming_Language_, 2nd edition, section 2.3, p. 39:
	The first name in an enum has value 0, the next 1, and so on, unless
	explicit values are specified.  If not all values are specified,
	unspecified values continue the progression from the last specified
	value...

I don't know what the 1st edition says, but I think that if TC truly claims
what you said, they are definitely in a very grey area, if not out-and-out
wrong.


> Barry L. Wallis			USENET: wallis@labc.dec.com
> Database Consultant		Prodigy (don't laugh): DNMX41A
> U.S. DECtp Resource Center	DECUServe: EISNER::WALLIS (not on the net yet)
> Los Angeles, CA			"No one voted for me, I represent myself"
> ---


Dave Schaumann			| "The really well that is suprising partner in
Dept. of Computer Science	| crime is that a lot and his wife of the
University of Arizona		| lion's feeding time we may be C D effectively
Tucson, AZ			| quite unaware of the fact that we are even
				| doing it."  -Python, on word association.

evan@plx.UUCP (Evan Bigall) (03/24/90)

>In article <1990Mar22.053148.10351@ncsuvx.ncsu.edu>, dks@shumv1.uucp (D. K. Smith) writes:
>The point of enums is that they offer more flexability than using #define.
>For example, say you had a list of 100 symbols you wanted to use as constants.
>Of course, order is important.  So, you type out 100 #defines.  Ok, fine.
>Suddenly, you discover you need a new symbol, which should go between the
>third and forth symbols.  If you use defines, you are pretty much stuck
>retyping the values on 97 defines.

I hate to do this, but this is what emacs is all about.
The following function (probably poor):

(defun increment-string (inc)
  "Find the next number in the current buffer and increment it
   leaveing point at the beginning of the number"
 (interactive "p")
 (let (beg end)                        
   (skip-chars-forward "^[0-9]")
   (setq beg (point))
   (skip-chars-forward "[0-9]")
   (setq end (point))
   (insert (int-to-string 
    (+ inc (string-to-int (buffer-substring beg end)))))
   (goto-char beg)
   (delete-region beg end)))

Allows you to write keyboard macros that trivialize this sort of editing.

The ability to count and do relative numeric edits is my test to anybody that
trys to espouse any other editor.

Evan

-- 
Evan Bigall, Plexus Software, Santa Clara CA (408)982-4840  ...!sun!plx!evan
"I barely have the authority to speak for myself, certainly not anybody else"

jlg@lambda.UUCP (Jim Giles) (03/24/90)

From article <1990Mar23.234509.21638@aqdata.uucp>, by sullivan@aqdata.uucp (Michael T. Sullivan):
> [...]
> typedef enum { red, green, brown, yellow } colors;
> typedef enum { huey, dewey, louie } ducks;
> main(){
> colors	a;
> ducks	b;
> 	a = red;
> 	b = huey;
> 	a = 1
> 	a = b;
> }
> produces a compiler error at "a = 1" and "a = b".  This makes sure people 
> can't make an end run around the values a given variable should have,
> which they could easily do if #define's were used for the values.

Really?  The new standard doesn't say that those assignemnts are illegal.
For example:
      "The identifiers in an enumerator list are declared as constants
       that have type int and may appear wherever such are permitted."

So, all the enumeration constants are just type int (in fact, red ==0,
green == 1, brown == 2, yellow == 3, huey == 0, dewey == 1, and
louie == 2).

Furthermore:
      "An object that has an enumeration type behaves like an int in
       an expression.  The implementation may use the set of values
       in the enumeration to determine whether to allocate less storage
       than an int."

In other words, the a and b vars behave as int except they may require
less storage.  So, all the assignments in your example are legal.

J. Giles

Note: The quotes above are from the last public review draft and
      not the new standard.  When (and if) I get a copy of the new
      standard, I will no longer be stuck with a possible source
      of wrong information.  If what I just quoted has been changed
      in the final standard, I want to be told.  There can't have
      been too many changes though since that would have required
      yet another public review.
> Michael Sullivan          uunet!jarthur!aqdata!sullivan
> aQdata, Inc.              sullivan@aqdata.uucp
> San Dimas, CA             +1 714 599 9992

Markku.Savela@tel.vtt.fi (Markku Savela) (03/24/90)

>In article <1990Mar22.053148.10351@ncsuvx.ncsu.edu> dks@shumv1.ncsu.edu (D. K. Smith) writes:
>>... I have not RTFM'd the C scriptures but my 
>>immediate reaction is "what's the point!...I could just as easily
>>used #define and accomplished the same thing.  

   There is one difference between #define and enum: you can do

	enum x { foo, bar, and, boo };
	...
	...
	int oops(foo)
	char *foo;
	  {
	     ...
	  }

   if you had "#define foo 0", you would at least get interesting
error messages from the compiler, not always quite easy to fathom,
unless you know to watch this situation...

   And, yes defining that kind of common names with #define is not
healthy. I don't usually do it, but got bitten by this when I
automaticly translated from Pascal to C (which converted Pascal
CONST-declarations to #define's ;-)  In a large program with
many included header files, it took a while until I realized what
the completely "bogus" error messages meant...



--
Markku Savela                         | savela@tel.vtt.fi
Technical Research Centre of Finland  |
Telecommunications Laboratory         | Markku.Savela@vtt.fi
Otakaari 7 B, SF-02150 ESPOO, Finland | savela%vtttel@router.funet.fi 

davidsen@sixhub.UUCP (Wm E. Davidsen Jr) (03/25/90)

In article <1990Mar22.164943.10459@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:

| Enumerated types were basically a kludge.  X3J11 seriously debated leaving
| them out entirely.  Arguments about not breaking existing code, etc, led
| to them being left in, but as a flavor of integer rather than as real live
| independent types.  That's all they ever were in C.

  A real kludge! Someone at an X3J11 meeting told me that enums were
added to the language by someone because the preprocessor was out of
symbol table and it was easier to hack the compiler than to expand the
preprocessor to allow more defines. I can't swear that's true, but no
one at the table seemed to find the idea shocking, unlikely, or even
new.

  I would really like to see a real enum in C, one of the things I think
was really done badly in the name of not breaking existing programs.

  I was told that enums as I wanted them were "thinking like Pascal,"
and "not in the spirit of C." Majority rules.
-- 
bill davidsen - davidsen@sixhub.uucp (uunet!crdgw1!sixhub!davidsen)
    sysop *IX BBS and Public Access UNIX
    moderator of comp.binaries.ibm.pc and 80386 mailing list
"Stupidity, like virtue, is its own reward" -me

stead@beno.CSS.GOV (Richard Stead) (03/26/90)

In article <2308@plx.UUCP>, evan@plx.UUCP (Evan Bigall) writes:
> I hate to do this, but this is what emacs is all about.
> [some lisp and religious ravings deleted...]
> The ability to count and do relative numeric edits is my test to anybody that
> trys to espouse any other editor.

O gimme a break!
FLAME ON!
I see ADA wars has just about packed up and left this group and you want
EMACS wars.  Is this comp.lang.c or alt.misc?  You want numbers?  How about a
vi macro that does exactly what your emacs macro does:
:map I /[0-9]^[ix^[lma/[^0-9]^[?[0-9]^[a+1^Mx^[`ai^M^[!!bc^[J2xkJh2x
Satisfied?
Flame off.
The point that was being addressed is that lots of #defines can be gross and
hard to maintain, setting up an emacs macro to address part of the maintainance
problem is not an answer.  One of the points of C is portability.  Are you
going to require everyone who wants to maintain your code learn both emacs
and lisp and use all your personal macros for that?  Bye bye portability.
So we're back to enums, a more portable solution for improved maintainability.

Richard Stead
stead@seismo.css.gov

karl@haddock.ima.isc.com (Karl Heuer) (03/27/90)

In article <699@sixhub.UUCP> davidsen@sixhub.UUCP (bill davidsen) writes:
>I was told that enums as I wanted them were "thinking like Pascal,"
>and "not in the spirit of C."

That's what they said about pointer-vs-integer collision detection, too.  An
idea is *not* automatically bad just because Pascal implemented it first!

ANSI decided to endorse the weak-enum model, but they did give a nod to the
strong-enum model via an acknowledement in the Common Warnings appendix.  I
presume there are a fair number of us who use enums only in the strong model,
so there ought to be a market for a compiler (or a lint option) that enforces
the stricter rules.  Unfortunately, even "gcc -Wall" doesn't seem to do so
yet, but I bet it could be added without too much difficulty.

In my opinion, the rules for strong-enum arithmetic should be analogous to
pointers: enum + int --> enum; enum - enum --> int; enum + enum --> error.
"++" and "--" are analogous to Pascal's "succ" and "pred" functions.  The one
thing you still can't do--and which was, I think, a major reason why the
Committee went for the weak-enum model--is to have an array subscripted by
enum, but this could be faked with a macro.

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

dave@aspect.UUCP (Dave Corcoran) (03/27/90)

In article <2308@plx.UUCP>, evan@plx.UUCP (Evan Bigall) writes:
> >In article <1990Mar22.053148.10351@ncsuvx.ncsu.edu>, dks@shumv1.uucp (D. K. Smith) writes:
> >Of course, order is important.  So, you type out 100 #defines.  Ok, fine.
> >Suddenly, you discover you need a new symbol, which should go between the
> >third and forth symbols.  If you use defines, you are pretty much stuck
> >retyping the values on 97 defines.

one reason I like macro assemblers :-)

> 
> I hate to do this, but this is what emacs is all about.
> The following function (probably poor):
> 
> [ solution using emacs deleted ]

here's my contribution using m4

script/definition file:

divert(-1)
define(LINE,0)
define(bump,`define(`LINE',incr(LINE))')
define(offset,``#define' $1 LINE bump')
define(init,`define(`LINE',$1)')
divert
/* <<m4>> */

source file:

init(1)
offset(one)
offset(two)
offset(three)
init(0)
offset(won)
offset(too)
offset(tree)

result:

/* <<m4>> */

#define one 1 
#define two 2 
#define three 3 

#define won 0 
#define too 1 
#define tree 2 

--

David C.
uunet!aspect!dave