rogue@cellar.UUCP (Rogue Winter) (04/18/91)
When I wanted to start learning C, I expected enumerated types to be very useful in combination with the increment and decrement operators. I hoped to be able to use printf(...%s...) to show the named value I'd given a constant. Neither experiment had the desired effect. I'm sure you all know the results of such operations involved. The point is, if increment operators on enumerated variables don't produce increments of the defined values in the enum statement (and enumerated variables are capable of having values not included in the explicit declarations), why bother declarig values for them? If the names given to enumerated values cannot be printed, why do they exist? The only purpose I can see is that they become local symbolic constants. Forgive a young novice her screed, but this just don't seem kosher. Rogue Winter : "How can you say I only protected people in South rogue@cellar.uucp : Philadelphia? I protected people all over this city; it uunet!cellar!rogue: didn't matter if they were in South Philadelphia or Cellar 215/3369503: Northeast Philadelphia." -- Frank Rizzo, 4/12/91
u-beasth%peruvian.utah.edu@cs.utah.edu (bryant eastham) (04/18/91)
Why ignore a construct that CAN give a clearer meaning to your programs? Using an enum can: 1) Allow a sequence of values to be assigned to identifiers without a bunch of #defines. (Not really a big benefit.) 2) Allow the compiler to flag type violations on those constants. The other option would allow any integer to be passed, where using an enum can be checked. This is a considerable advantage. In general: Use what they give you to the best advantage! Bryant Eastham A programmer who cannot live without nested #includes OR enums.
henry@zoo.toronto.edu (Henry Spencer) (04/18/91)
In article <gu1k13w164w@cellar.UUCP> rogue@cellar.UUCP (Rogue Winter) writes: >If the names given to enumerated values cannot be printed, why do they exist? Rumor hath it that they were an implementation kludge after somebody ran out of symbol-table space in the preprocessor and couldn't expand it because of address-space limitations on an old machine. The fast answer is that, as you have surmised, they aren't good for much. They don't fit the rest of the language very well, and they were never thought through very clearly until X3J11 tried to figure out what they should mean in ANSI C... at which point it was discovered that existing implementations varied so much that it was impossible to do anything ambitious with them. I'm told that there was considerable sentiment for leaving them out of ANSI C entirely. Just ignoring them is the simplest thing to do. -- And the bean-counter replied, | Henry Spencer @ U of Toronto Zoology "beans are more important". | henry@zoo.toronto.edu utzoo!henry
torek@elf.ee.lbl.gov (Chris Torek) (04/19/91)
>>[enumerated types are ridiculously weak; why do they exist at all?] In article <1991Apr18.153418.13527@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >Just ignoring them is the simplest thing to do. It is sometimes nice to have a symbolic debugger print state = TCPSTATE_ESTABLISHED or whatever, and it is sometimes nice to allow the compiler to choose the types and values of enumeration variables and constants. A few compilers will also warn about `mixed up' enumerations (enum apple with enum orange). That makes three tiny points in favour :-) -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
pds@lemming.webo.dg.com (Paul D. Smith) (04/19/91)
[] On 18 Apr 91 04:26:15 GMT, rogue@cellar.UUCP (Rogue Winter) said: RW> If the names given to enumerated values cannot be printed, why do RW> they exist? The only purpose I can see is that they become local RW> symbolic constants. They are basically just for the edification of the programmer. It is a handy way to state that a variable of the enum type should contain one of the enumerated values, and no others. With a regular preprocessor constant there is nothing to indicate that the variable can't contain other values, short of putting in a comment to that effect. With enums the compiler could generate a warning. Some compilers can pick the size of the integer in which the enum is stored based on the size of the largest (or sometimes smallest) number: thus if your enum values were only 1-5 you'd get a short or even a char, but if your values contained something like 1000000 you get an int or long (depending on your architecture). Usually this is only useful to try to force all enums to be the native size of the CPU (since this is the most efficient size), unless they absolutely can't fit. Also, most modern debuggers are quite good at noticing when something is an enum and *do* in fact print the symbolic form (usually in addition to the numeric form) during debugging. This makes it quite handy from the programmer's point of view. If you think about it, there is no way you could have enums be printable in string form without introducing some new syntax into C: how would the compiler know when to interpret the value of the variable as an integer (enum) and when to interpret it as a string? The compiler obviously can't recognize that you're passing the enum to a printf with a "%s" argument, so what if you just wanted to pass the value of the enum to a function? You'd need some new syntax to say "use the stringified name of this enum" rather than the enum value. All in all, enums are just syntactic sugar. But some syntactic sugar can make your programming life much nicer, IMHO, and enums do this quite well without getting in the way of the "spirit of C". paul ----- ------------------------------------------------------------------ | Paul D. Smith | pds@lemming.webo.dg.com | | Data General Corp. | | | Network Systems Development Division | "Pretty Damn S..." | | Open Network Systems Development | | ------------------------------------------------------------------
toma@swsrv1.cirr.com (Tom Armistead) (04/19/91)
In article <gu1k13w164w@cellar.UUCP> rogue@cellar.UUCP (Rogue Winter) writes: >When I wanted to start learning C, I expected enumerated types to be very >useful in combination with the increment and decrement operators. I hoped to >be able to use printf(...%s...) to show the named value I'd given a constant. > >Neither experiment had the desired effect. I'm sure you all know the results >of such operations involved. The point is, if increment operators on >enumerated variables don't produce increments of the defined values in the >enum statement (and enumerated variables are capable of having values >not included in the explicit declarations), why bother declarig values for >them? > >If the names given to enumerated values cannot be printed, why do they exist? >The only purpose I can see is that they become local symbolic constants. > >Forgive a young novice her screed, but this just don't seem kosher. > >Rogue Winter : "How can you say I only protected people in South >rogue@cellar.uucp : Philadelphia? I protected people all over this city; it >uunet!cellar!rogue: didn't matter if they were in South Philadelphia or >Cellar 215/3369503: Northeast Philadelphia." -- Frank Rizzo, 4/12/91 A few reasons for enums: When in a symbolic debugger, you can display an enum variables contents and get the text associated with the value, where a define only shows the value (unless you have a really smart debugger). When used in a switch statememt for some C compilers), will not let you have case elements that aren't part of the emumeration. (i.e. better type checking). I've used enum's to generate some pretty complex types where certain bit patterns made something belong to a certain class. After getting this set up, it was very easy to just insert a new element in the middle of the enum, where using defines would have caused me to do math for each element I added. From the Second Edition of K&R: page 39 Enumerations provide a convenient way to associate constant values with names, an alternative to #define with the advantage that values can be generated for you. ... Tom -- Tom Armistead - Software Services - 2918 Dukeswood Dr. - Garland, Tx 75040 =========================================================================== toma@swsrv1.cirr.com {egsner,letni,ozdaltx,void}!swsrv1!toma
ts@cup.portal.com (Tim W Smith) (04/19/91)
Wow! Both Henry Spencer and Chris Torek missed the point of enumerated types... next thing you know, getting involved in a land war in Asia will be a good idea. Anyway, the real point is to allow lower case names for constants. If you try this in a header file: #define opened 1 #define closed 2 everyone will scream that you should have said #define OPENED 1 #define CLOSED 2 whereas, if you instead go enum state { opened=1, closed }; people who read the code will be so busy trying to remember what the heck and 'enum' is that they won't realize you've snuck in lower case constant names. Tim Smith
steve@taumet.com (Stephen Clamage) (04/21/91)
ts@cup.portal.com (Tim W Smith) writes: >Anyway, the real point is to allow lower case names for constants. If >you try this in a header file... "The" real point, eh? Seems like we've have more than one good point mentioned already, but I haven't seen this one yet: Preprocessor defines have no scope. They reach into the internals of structs and functions and can result in mystifying error messages and hard-to-find bugs. The enumeration names are scoped, and can be made local to functions if desired, and can be locally overridden inside functions which don't know and don't want to know about a #define (or enum) buried inside some nested include file. -- Steve Clamage, TauMetric Corp, steve@taumet.com
burow@cernvax.cern.ch (burkhard burow) (04/21/91)
[] On 18 Apr 91 04:26:15 GMT, rogue@cellar.UUCP (Rogue Winter) said: RW> If the names given to enumerated values cannot be printed, why do RW> they exist? The only purpose I can see is that they become local RW> symbolic constants. Below, in enum.h, is a souped up 'enum' and an example program follows in enum.c. Cut 'em out, compile, and a demo's ready for you. In no more code than a regular typedef enum, the macros ENUMn(...), where n is the number of constants in the enumeration, provides: i) the constants. ii) the number of constants. iii) an array of the constant names as strings. iv) a macro to recognize a particular constant in the enumeration. v) addition of another constant to the enumeration without changing a single line of code elsewhere. WARNING: In the following, as far as I know, the only deviation from ANSI C is the '/**/' kludge for the preprocessor concatenation operator '##'. I use ENUMn on: VAX VMS: C 3.1 and MIPS Computer Systems 2.0 (e.g. SGI and DECstations). Some 'guidelines' for these two machines are given in enum.h. May it amuse, burkhard burow@vxdesy.cern.ch ------------cut here for enum.c------------------------------------------------ /* enum.c An example of the macros in enum.h */ /* Burkhard Burow, University of Toronto, 1990. */ #include "enum.h" #include <stdio.h> #define MIN(A,B) ((A)<(B)?(A):(B)) /* Note that adding another constant to the following line requires no change in any other line of code. */ #ifndef mips ENUM5(LIST, JUST, SOME, SILLY, STUFF, AGAIN); #else ENUM5(LIST,JUST,SOME,SILLY,STUFF,AGAIN); #endif main () { int i, loop; char s[99]; LIST list; puts("The enum 'LIST' has the following enumerated constants."); for (i=0; i<(int)LISTS; i++) printf(" %s", enum_str(LIST)[i]); puts("\n Please enter one of the above constants: "); gets(s); for (loop=0; loop<4; loop++) { switch (loop) { case 0: printf("An exact comparison"); ENUMno(LIST, s, 9999, i); break; case 1: printf("A comparison of the first strlen('LIST' element) characters"); ENUMno(LIST, s, strlen(enum_str(LIST)[i]), i); break; case 2: printf("A comparison of the first strlen(%s) characters",s); ENUMno(LIST, s, strlen(s), i); break; case 3: printf("A comparison of the first "); printf("MIN(strlen(%s), strlen('LIST' element) ) characters", s); ENUMno(LIST, s, MIN(strlen(s),strlen(enum_str(LIST)[i])), i); break; } if (i==(int)LISTS) printf("\n does not recognize %s as a constant in 'LIST'\n\n", s); else printf("\n recognizes %s as the constant %s in 'LIST'\n\n", s, enum_str(LIST)[i]); } } ------------cut here for enum.h------------------------------------------------ /* enum.h */ /* Burkhard Burow, University of Toronto, 1990. */ #ifndef __ENUM_LOADED #define __ENUM_LOADED 1 static char *nonindent(char *s) { while(*s==' ')s++; return s; } #include <stdio.h> #include <string.h> /* Souped up enum => ENUM1->ENUMn. Typedef's NAME as enumerated with the n given constants. enum_str(NAME) is an array of the constants as strings and NAMES is the number of constants. Macro ENUMno recognizes constant from a string. VAX WARNING: The arguments to ENUMn should be be immediately followed by the ',' or ')'. Trailing whitespace characters are part of the argument, and as such will be included in the string created for each tag and hence will cause difficulties when ENUMno searching for tags. MIPS WARNING: Same as the VAX but space after the comma and before the argument is also included in that argument. Therefore to maintain portability across VAXen and MIPS', remove all spaces in ENUMi(...) and in enum_str(...) calls. Alternatively, to preserve readability, use #ifndef mips for calls to ENUMi(..) and enum_str(...) with spaces for readability and behind the #else have the same calls with all spaces removed. N.B. MIPS machines include SGI's and DECstations. */ #define enum_str(NAME) ENUM_/**/NAME #define ENUMNO(ENUM_NAME, NAMES, STRING, LENGTH, NO) \ for (NO=0; NO<(int)NAMES; NO++) \ if (strncmp(STRING,ENUM_NAME[NO],LENGTH)==0) break; #define ENUMno(NAME, STRING, LENGTH, NO) \ ENUMNO(enum_str(NAME), NAME/**/S, STRING, LENGTH, NO) /* char *ENUM_NAME[]; int NAMES; char *STRING; int LENGTH; int NO; - NO returns enum. tag of ENUM_NAME matching LENGTH characters of STRING. - If none of the NAMES tags match STRING, NO returns NAMES. - For exact comparison with STRING use LENGTH as a_really_big_int. - For prefix comparison on STRING use LENGTH as strlen(ENUM_NAME[NO]). - For prefix comparison on ENUM_NAME's use LENGTH as strlen(STRING). - For prefix comparison on either use LENGTH as MIN(strlen(STRING),STRLEN(ENUM_NAME[NO])). */ #define ENUM1(NAME, A) typedef enum{A,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A"} #define ENUM2(NAME, A,B) typedef enum{A,B,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B"} #define ENUM3(NAME, A,B,C) typedef enum{A,B,C,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C"} #define ENUM4(NAME, A,B,C,D) typedef enum{A,B,C,D,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D"} #define ENUM5(NAME, A,B,C,D,E) typedef enum{A,B,C,D,E,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E"} #define ENUM6(NAME, A,B,C,D,E,F) typedef enum{A,B,C,D,E,F,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F"} #define ENUM7(NAME, A,B,C,D,E,F,G) \ typedef enum{A,B,C,D,E,F,G,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G"} #define ENUM8(NAME, A,B,C,D,E,F,G,H) \ typedef enum{A,B,C,D,E,F,G,H,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H"} #define ENUM11(NAME, A,B,C,D,E,F,G,H,I,J,K) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K"} #define ENUM12(NAME, A,B,C,D,E,F,G,H,I,J,K,L) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L"} #define ENUM13(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M"} #define ENUM15(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O"} #define ENUM16(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P"} #define ENUM20(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U"} #define ENUM46(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,NAME/**/S}NAME;\ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV"} #define ENUM48(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX, \ NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX"} #define EXPAND16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) \ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P #define QEXPAND16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P) \ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P" /* N.B. e.g. ENUM78(NAME, 52 args, (16 args) ) req.d because VAX C limits number of macro args to 64. */ #define ENUM78(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,ARGS16) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,EXPAND16/**/ARGS16,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX","AY","AZ", \ "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL", \ QEXPAND16/**/ARGS16} #define EXPAND18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) \ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R #define QEXPAND18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R) \ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R" /* N.B. ENUM80(NAME, 52 args, (18 args) ) syntax req.d because VAX C limits number of macro args to 64. */ #define ENUM80(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,ARGS18) \ typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z, \ AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ, \ BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,EXPAND18/**/ARGS18,NAME/**/S}NAME; \ static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \ "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \ "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK", \ "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX","AY","AZ", \ "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL", \ QEXPAND18/**/ARGS18} #endif /* __ENUM_LOADED */
marks@cbnewsl.att.com (mark.e.smith) (04/22/91)
In article <678@taumet.com> steve@taumet.com (Stephen Clamage) writes: >ts@cup.portal.com (Tim W Smith) writes: > >>Anyway, the real point is to allow lower case names for constants. If >>you try this in a header file... > I love it. Score one for the anti-style guide side. > >Preprocessor defines have no scope. They reach into the internals of >structs and functions and can result in mystifying error messages and >hard-to-find bugs. The enumeration names are scoped, and can be made >local to functions if desired, and can be locally overridden inside >functions which don't know and don't want to know about a #define (or >enum) buried inside some nested include file. Yes. The answer hints at the model, which is that an enum defines a type, i.e. a set of values. Defining types is a Good Thing. Otherwise, there's nothing in the program syntax which hints at the relationship among the values. Compare for example the three styles: #define APPLE 1 #define ORANGE 2 vs. #define APPLE 1 #define ORANGE ( APPLE + 1 ) which is better, since at least we have some clue that an apple and an orange are somehow related; vs. enum { APPLE = 1, ORANGE } ; which is explicit. Mark Smith
rogue@cellar.UUCP (Rogue Winter) (04/25/91)
ts@cup.portal.com (Tim W Smith) writes: > Wow! Both Henry Spencer and Chris Torek missed the point of enumerated > types... next thing you know, getting involved in a land war in Asia > will be a good idea. > > Anyway, the real point is to allow lower case names for constants. If > [code deleted, The President's previous statements are inoperable] > people who read the code will be so busy trying to remember what the > heck and 'enum' is that they won't realize you've snuck in lower case > constant names. > > Tim Smith Well, since I'm self-taught and don't have anyone looking over my shoulder at my bad habits, I tend to violate such canons amyhow. I've used all caps to define constants and mixed case to define macros and nobody else has ever had to know the wiser. (oops, now I've just blurted it out) Since the only reason I sould come up with for using enums was as an alternate declaration of constants, I had to consider it useless, since it takes more expressions to use an enum variable than a defined constant. Rogue Winter : "How can you say I only protected people in South rogue@cellar.uucp : Philadelphia? I protected people all over this city; it uunet!cellar!rogue: didn't matter if they were in South Philadelphia or Cellar 215/3369503: Northeast Philadelphia." -- Frank Rizzo, 4/12/91