Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #162848 > unrolled thread
| Started by | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| First post | 2021-09-27 10:39 -0700 |
| Last post | 2021-09-29 03:40 +0000 |
| Articles | 20 on this page of 49 — 13 participants |
Back to article view | Back to comp.lang.c
redeclaration of enumerators? Thiago Adams <thiago.adams@gmail.com> - 2021-09-27 10:39 -0700
Re: redeclaration of enumerators? John Bode <jfbode1029@gmail.com> - 2021-09-28 16:21 -0500
Re: redeclaration of enumerators? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-09-28 14:57 -0700
Re: redeclaration of enumerators? Thiago Adams <thiago.adams@gmail.com> - 2021-09-28 15:23 -0700
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-09-29 15:23 +0200
Re: redeclaration of enumerators? Mark Bluemel <mark.bluemel@gmail.com> - 2021-09-30 01:15 -0700
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-09-28 23:31 +0100
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-09-29 15:36 +0200
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-09-29 15:03 +0100
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-09-29 16:46 +0200
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-09-29 16:08 +0100
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-09-29 20:14 +0200
Re: redeclaration of enumerators? Thiago Adams <thiago.adams@gmail.com> - 2021-09-29 13:37 -0700
Re: redeclaration of enumerators? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-09-29 18:25 -0700
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-09-30 12:45 +0200
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-09-30 07:36 -0700
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-10-01 09:20 +0200
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 11:24 +0100
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-10-01 04:49 -0700
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 13:06 +0100
Re: redeclaration of enumerators? Tony Oliver <guinness.tony@gmail.com> - 2021-10-01 05:24 -0700
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 13:32 +0100
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-10-01 05:32 -0700
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 13:43 +0100
Re: redeclaration of enumerators? Mark Bluemel <mark.bluemel@gmail.com> - 2021-10-01 06:13 -0700
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-10-01 06:29 -0700
Re: redeclaration of enumerators? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-10-01 15:30 +0100
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-10-01 08:28 -0700
Re: redeclaration of enumerators? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-10-01 17:08 +0100
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-10-01 15:12 -0700
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-10-01 15:37 +0200
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 15:30 +0100
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-10-01 19:12 +0200
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 19:06 +0100
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-10-01 15:32 +0200
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 15:38 +0100
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-01 17:40 +0100
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-02 12:16 +0100
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-10-02 15:34 +0200
Re: redeclaration of enumerators? Bart <bc@freeuk.com> - 2021-10-02 15:16 +0100
Re: redeclaration of enumerators? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-10-01 13:58 -0700
Re: redeclaration of enumerators? Richard Damon <Richard@Damon-Family.org> - 2021-10-01 17:21 -0400
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-10-01 14:56 -0700
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-10-02 12:21 +0200
Re: redeclaration of enumerators? scott@slp53.sl.home (Scott Lurndal) - 2021-09-30 14:47 +0000
Re: redeclaration of enumerators? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2021-09-30 10:10 -0700
Re: redeclaration of enumerators? David Brown <david.brown@hesbynett.no> - 2021-10-01 09:24 +0200
Re: redeclaration of enumerators? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-09-29 12:43 -0700
Re: redeclaration of enumerators? Branimir Maksimovic <branimir.maksimovic@gmail.com> - 2021-09-29 03:40 +0000
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | Tony Oliver <guinness.tony@gmail.com> |
|---|---|
| Date | 2021-10-01 05:24 -0700 |
| Message-ID | <175c929c-4a6b-4319-8158-0cdd9099b03dn@googlegroups.com> |
| In reply to | #162893 |
On Friday, 1 October 2021 at 13:06:56 UTC+1, Bart wrote:
> At the moment, C allows:
>
> enum { red=1, green=1, blue=1 };
>
> enum { red=1000000000, green=2000000000, blue=-2000000000 };
It most certainly doesn't:
enums.c:2:8: error: redeclaration of enumerator ‘red’
enum { red=1000000000, green=2000000000, blue=-2000000000 };
^~~
enums.c:1:8: note: previous definition of ‘red’ was here
enum { red=1, green=1, blue=1 };
^~~
enums.c:2:24: error: redeclaration of enumerator ‘green’
enum { red=1000000000, green=2000000000, blue=-2000000000 };
^~~~~
enums.c:1:15: note: previous definition of ‘green’ was here
enum { red=1, green=1, blue=1 };
^~~~~
enums.c:2:42: error: redeclaration of enumerator ‘blue’
enum { red=1000000000, green=2000000000, blue=-2000000000 };
^~~~
enums.c:1:24: note: previous definition of ‘blue’ was here
enum { red=1, green=1, blue=1 };
^~~~
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 13:32 +0100 |
| Message-ID | <sj6v4s$3km$1@dont-email.me> |
| In reply to | #162894 |
On 01/10/2021 13:24, Tony Oliver wrote:
> On Friday, 1 October 2021 at 13:06:56 UTC+1, Bart wrote:
>> At the moment, C allows:
>>
>> enum { red=1, green=1, blue=1 };
>>
>> enum { red=1000000000, green=2000000000, blue=-2000000000 };
>
> It most certainly doesn't:
>
> enums.c:2:8: error: redeclaration of enumerator ‘red’
> enum { red=1000000000, green=2000000000, blue=-2000000000 };
> ^~~
> enums.c:1:8: note: previous definition of ‘red’ was here
> enum { red=1, green=1, blue=1 };
> ^~~
> enums.c:2:24: error: redeclaration of enumerator ‘green’
> enum { red=1000000000, green=2000000000, blue=-2000000000 };
> ^~~~~
> enums.c:1:15: note: previous definition of ‘green’ was here
> enum { red=1, green=1, blue=1 };
> ^~~~~
> enums.c:2:42: error: redeclaration of enumerator ‘blue’
> enum { red=1000000000, green=2000000000, blue=-2000000000 };
> ^~~~
> enums.c:1:24: note: previous definition of ‘blue’ was here
> enum { red=1, green=1, blue=1 };
> ^~~~
>
I didn't mean at the same time!
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2021-10-01 05:32 -0700 |
| Message-ID | <6ce76fc9-f5ce-4cb4-9750-326b0a0a2ce0n@googlegroups.com> |
| In reply to | #162893 |
On Friday, 1 October 2021 at 13:06:56 UTC+1, Bart wrote:
> On 01/10/2021 12:49, Malcolm McLean wrote:
> > On Friday, 1 October 2021 at 11:24:29 UTC+1, Bart wrote:
> >> On 01/10/2021 08:20, David Brown wrote:
> >>> On 30/09/2021 16:36, Malcolm McLean wrote:
> >>>> On Thursday, 30 September 2021 at 11:45:50 UTC+1, David Brown wrote:
> >>>>>
> >>>>> But I think that in most cases, it is not at all helpful to think about
> >>>>> the underlying integer values. You get cleaner, safer, more portable
> >>>>> code if you treat the enumeration constants as being abstract symbols
> >>>>> that are members of the particular type without any other semantics or
> >>>>> meaning.
> >>>>>
> >>>> I agree, but there are some snags. One is if you wish to print out the enum
> >>>> for debug purposes. It's easy enough to write printf("light %d\n", (int) lightenumval);
> >>>> If you have to set up an enum to string function then it's a bit clearer, but it's a huge
> >>>> hassle for debug.
> >>>> The other snag is that often you want to use the enum to index into a table
> >>>> of some sort. Again, you can set up a system by writing a switch, but that's
> >>>> likely slower and more code.
> >>>>
> >>>
> >>> These are not "snags" - they are cases where the underlying integer
> >>> value of the enumeration constants is sometimes helpful due to the
> >>> limitations of the language. Eventually, C++ will get some decent
> >>> compile-time reflection capabilities that will allow you to generate
> >>> strings from enumeration constants simply and easily, without repetition
> >>> in the code (and without complicated X-macros).
> >>>
> >>> In the meantime, C99, and C++ with gcc extensions (unfortunately not
> >>> standard), let you write:
> >>>
> >>>
> >>> typedef enum Colours { red, green, blue } Colours;
> >>>
> >>> extern const char * const colour_names[];
> >>> const char * const colour_names[] = {
> >>> [red] = "red",
> >>> [green] = "green",
> >>> [blue] = "blue",
> >>> };
> >> This is not ideal:
> >>
> > For some purposes you really need a special function called something like "enum_to_string",
> > as David Brown implied. Then const char *name = enum_to_string(red), sets name to "red".
> > That would be good for debug messages,
> >
> > printf("Car crashed lights were %s\n", enum_to_string( lightvalue));
> >
> > maybe you could also use it in a database
> >
> > struct crashrecord
> > {
> > double speed;
> > bool aidrivingon;
> > char lasttrafficlights[8]; // red, amber, green
> > };
> >
> > However it wouldn't normally be acceptable for user-facing strings.
> >
> > To implement, you would need enums to be types, then enum_to_string would be a bit like
> > "sizeof", a function (maths sense) which isn't a subroutine but a keyword.
> >
> It would need a bit more than that. At the moment, C allows:
>
> enum { red=1, green=1, blue=1 };
>
> enum { red=1000000000, green=2000000000, blue=-2000000000 };
>
> There are no restrictions at all. Think about how to_string might work
> for any of these values. The first lot are impossible; the second,
> inefficient.
>
> Think also about using these as switch-case values, or array indices, as
> I noted.
>
> So the first step would be a special king of enum where the names are
> inter-related and have a distinct, compact range of underlying values,
> ideally consecutive.
>
There are three distinct situations I see.
The first is where the enum is a flag or comibation of flags which is used to
pass multiple booleans /small integers efficiently.
The second is where the enum is a collection of labels which defines a set,
but where there is no paticular mathematical relationship. For example
amino acids in proteins.
The third is where you have a relationship such that the members are ordered.
This might be a natural order (BABY, TODDLER, CHILD, TEENAGER, YOUTH,
MIDDLEAGED, PENSIONER), or it might be a strong social convention (A, B, C ...).
The other logical situation is an ordering, with the added stipulation that the
intervals be the same. I suggest that an enum is not suitable for this kind
of data. If the intervals are the same, they must be based on some mathematical
measure,and it's best to store that value explicitly.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 13:43 +0100 |
| Message-ID | <sj6vp3$9b0$1@dont-email.me> |
| In reply to | #162895 |
On 01/10/2021 13:32, Malcolm McLean wrote:
> On Friday, 1 October 2021 at 13:06:56 UTC+1, Bart wrote:
>> On 01/10/2021 12:49, Malcolm McLean wrote:
>>> For some purposes you really need a special function called something like "enum_to_string",
>>> as David Brown implied. Then const char *name = enum_to_string(red), sets name to "red".
>>> That would be good for debug messages,
>>>
>>> printf("Car crashed lights were %s\n", enum_to_string( lightvalue));
>>>
>>> maybe you could also use it in a database
>>>
>>> struct crashrecord
>>> {
>>> double speed;
>>> bool aidrivingon;
>>> char lasttrafficlights[8]; // red, amber, green
>>> };
>>>
>>> However it wouldn't normally be acceptable for user-facing strings.
>>>
>>> To implement, you would need enums to be types, then enum_to_string would be a bit like
>>> "sizeof", a function (maths sense) which isn't a subroutine but a keyword.
>>>
>> It would need a bit more than that. At the moment, C allows:
>>
>> enum { red=1, green=1, blue=1 };
>>
>> enum { red=1000000000, green=2000000000, blue=-2000000000 };
>>
>> There are no restrictions at all. Think about how to_string might work
>> for any of these values. The first lot are impossible; the second,
>> inefficient.
>>
>> Think also about using these as switch-case values, or array indices, as
>> I noted.
>>
>> So the first step would be a special king of enum where the names are
>> inter-related and have a distinct, compact range of underlying values,
>> ideally consecutive.
>>
> There are three distinct situations I see.
>
> The first is where the enum is a flag or comibation of flags which is used to
> pass multiple booleans /small integers efficiently.
>
> The second is where the enum is a collection of labels which defines a set,
> but where there is no paticular mathematical relationship. For example
> amino acids in proteins.
>
> The third is where you have a relationship such that the members are ordered.
> This might be a natural order (BABY, TODDLER, CHILD, TEENAGER, YOUTH,
> MIDDLEAGED, PENSIONER), or it might be a strong social convention (A, B, C ...).
>
> The other logical situation is an ordering, with the added stipulation that the
> intervals be the same. I suggest that an enum is not suitable for this kind
> of data. If the intervals are the same, they must be based on some mathematical
> measure,and it's best to store that value explicitly.
>
At least enums in C are still just aliases for integer values. (Look at
what 'enum' means in Rust.)
But your first category uses enums simply because C has no other
suitable features (#define and 'const int' have their own problems).
they are just arbitrary values.
Other examples for your other two categories are:
Spades, Clubs, Hearts, Diamonds
Mon, Tue, Wed, Thu, Fri, Sat, Sun
But if you look at the internal numbering, both are going be 0..3 or
0..6; that is, both sequential, both starting from the same value, and
both ordered.
So why can't that second category be assumed to be ordered, even if it
doesn't demand it?
You may have an array of such values, and may want to sort out it. It
would be useful to know which enums are going to occur first.
[toc] | [prev] | [next] | [standalone]
| From | Mark Bluemel <mark.bluemel@gmail.com> |
|---|---|
| Date | 2021-10-01 06:13 -0700 |
| Message-ID | <68395775-5e31-4621-be73-f9695ddd7bcfn@googlegroups.com> |
| In reply to | #162897 |
On Friday, 1 October 2021 at 13:43:27 UTC+1, Bart wrote: > At least enums in C are still just aliases for integer values. (Look at > what 'enum' means in Rust.) I just looked. It looks very similar to how they work in Java (my main programming language these days). Java enums - with associated data and behaviour - are really valuable in my opinion, but if you want enums to just be integers in disguise, fill your boots.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2021-10-01 06:29 -0700 |
| Message-ID | <71c81598-e3c5-4955-b818-8b271c48d39en@googlegroups.com> |
| In reply to | #162897 |
On Friday, 1 October 2021 at 13:43:27 UTC+1, Bart wrote:
> On 01/10/2021 13:32, Malcolm McLean wrote:
> > On Friday, 1 October 2021 at 13:06:56 UTC+1, Bart wrote:
> >> On 01/10/2021 12:49, Malcolm McLean wrote:
>
> >>> For some purposes you really need a special function called something like "enum_to_string",
> >>> as David Brown implied. Then const char *name = enum_to_string(red), sets name to "red".
> >>> That would be good for debug messages,
> >>>
> >>> printf("Car crashed lights were %s\n", enum_to_string( lightvalue));
> >>>
> >>> maybe you could also use it in a database
> >>>
> >>> struct crashrecord
> >>> {
> >>> double speed;
> >>> bool aidrivingon;
> >>> char lasttrafficlights[8]; // red, amber, green
> >>> };
> >>>
> >>> However it wouldn't normally be acceptable for user-facing strings.
> >>>
> >>> To implement, you would need enums to be types, then enum_to_string would be a bit like
> >>> "sizeof", a function (maths sense) which isn't a subroutine but a keyword.
> >>>
> >> It would need a bit more than that. At the moment, C allows:
> >>
> >> enum { red=1, green=1, blue=1 };
> >>
> >> enum { red=1000000000, green=2000000000, blue=-2000000000 };
> >>
> >> There are no restrictions at all. Think about how to_string might work
> >> for any of these values. The first lot are impossible; the second,
> >> inefficient.
> >>
> >> Think also about using these as switch-case values, or array indices, as
> >> I noted.
> >>
> >> So the first step would be a special king of enum where the names are
> >> inter-related and have a distinct, compact range of underlying values,
> >> ideally consecutive.
> >>
> > There are three distinct situations I see.
> >
> > The first is where the enum is a flag or comibation of flags which is used to
> > pass multiple booleans /small integers efficiently.
> >
> > The second is where the enum is a collection of labels which defines a set,
> > but where there is no paticular mathematical relationship. For example
> > amino acids in proteins.
> >
> > The third is where you have a relationship such that the members are ordered.
> > This might be a natural order (BABY, TODDLER, CHILD, TEENAGER, YOUTH,
> > MIDDLEAGED, PENSIONER), or it might be a strong social convention (A, B, C ...).
> >
> > The other logical situation is an ordering, with the added stipulation that the
> > intervals be the same. I suggest that an enum is not suitable for this kind
> > of data. If the intervals are the same, they must be based on some mathematical
> > measure,and it's best to store that value explicitly.
> >
> At least enums in C are still just aliases for integer values. (Look at
> what 'enum' means in Rust.)
>
> But your first category uses enums simply because C has no other
> suitable features (#define and 'const int' have their own problems).
> they are just arbitrary values.
>
> Other examples for your other two categories are:
>
> Spades, Clubs, Hearts, Diamonds
>
The traditional order of the suits is "Hearts, Clubs, Diamonds, Spades",
however in Bridge it is Clubs, Diamonds, Hearts, Spades, in Bridge
you would also want a value of "NoTrumps" for the contract, but not for
the card played.
>
> Mon, Tue, Wed, Thu, Fri, Sat, Sun
>
Tuesday follows Monday. We can also say that the step from Monday
to Tuesday is exactly the same as the step from Tuesday to Wednesday,
(though that's not true of months of course). Traditionally Sunday is
regarded as the first day of the week, but for business purposes many
organisation start the week at Monday.
These are the problems you get when trying to encode real data.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2021-10-01 15:30 +0100 |
| Message-ID | <87lf3ckebg.fsf@bsb.me.uk> |
| In reply to | #162895 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> There are three distinct situations I see.
>
> The first is where the enum is a flag or comibation of flags which is used to
> pass multiple booleans /small integers efficiently.
I would not call that an enum.
> The second is where the enum is a collection of labels which defines a set,
> but where there is no paticular mathematical relationship. For example
> amino acids in proteins.
Again, I'd not call that an enum. enum implies enumeration so there
should be a successor and predecessor operation.
> The third is where you have a relationship such that the members are ordered.
> This might be a natural order (BABY, TODDLER, CHILD, TEENAGER, YOUTH,
> MIDDLEAGED, PENSIONER), or it might be a strong social convention (A,
> B, C ...).
This one is an enum!
If I were making it up from a blank slate, I'd have collections of
symbols which might or might not be ordered:
NAMES { verbose, logging, no_splash } flags;
SET OF flags options;
/* succ(verbose) not defined but name_of(verbose) == "verbose" */
ORDERED NAMES { GCSE, A_Level, Degree, Postgraduate } qualifications;
/* succ(GCSE) == A_Level and ord(Degree) == 2 */
> The other logical situation is an ordering, with the added stipulation
> that the intervals be the same. I suggest that an enum is not suitable
> for this kind of data.
Except, presumably, when the interval is 1? That's almost the textbook
definition of an enumeration.
> If the intervals are the same, they must be
> based on some mathematical measure,and it's best to store that value
> explicitly.
I agree that this is much more specialised.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2021-10-01 08:28 -0700 |
| Message-ID | <44ae0b4e-5184-4459-94b9-c4ecd9ccde1an@googlegroups.com> |
| In reply to | #162903 |
On Friday, 1 October 2021 at 15:30:38 UTC+1, Ben Bacarisse wrote:
> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>
> > There are three distinct situations I see.
> >
> > The first is where the enum is a flag or comibation of flags which is used to
> > pass multiple booleans /small integers efficiently.
> I would not call that an enum.
> > The second is where the enum is a collection of labels which defines a set,
> > but where there is no paticular mathematical relationship. For example
> > amino acids in proteins.
> Again, I'd not call that an enum. enum implies enumeration so there
> should be a successor and predecessor operation.
> > The third is where you have a relationship such that the members are ordered.
> > This might be a natural order (BABY, TODDLER, CHILD, TEENAGER, YOUTH,
> > MIDDLEAGED, PENSIONER), or it might be a strong social convention (A,
> > B, C ...).
> This one is an enum!
>
> If I were making it up from a blank slate, I'd have collections of
> symbols which might or might not be ordered:
>
> NAMES { verbose, logging, no_splash } flags;
> SET OF flags options;
>
> /* succ(verbose) not defined but name_of(verbose) == "verbose" */
>
> ORDERED NAMES { GCSE, A_Level, Degree, Postgraduate } qualifications;
>
> /* succ(GCSE) == A_Level and ord(Degree) == 2 */
> > The other logical situation is an ordering, with the added stipulation
> > that the intervals be the same. I suggest that an enum is not suitable
> > for this kind of data.
> Except, presumably, when the interval is 1? That's almost the textbook
> definition of an enumeration.
>
The elements are an example. Hydrogen has one proton, Helium two,
Lithium three, and it goes up in steps of one proton. However the end
of the table is a bit fuzzy. Whilst not claiming to be a physicist, I don't
think we yet understand whether there is hard limit on how many protons
can fuse into a single atom or not. So there's an argument for using an integer
count of protons instead of an enum to represent elements.
However if the program is doing biochemistry, the heavy, unstable elements
are unlikely to feature. So you can just declare a "heaviest element we will
handle", and add a few entries to the enum if it proves that you were wrong.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2021-10-01 17:08 +0100 |
| Message-ID | <87fstkk9ra.fsf@bsb.me.uk> |
| In reply to | #162906 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> On Friday, 1 October 2021 at 15:30:38 UTC+1, Ben Bacarisse wrote:
>> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>>
>> > There are three distinct situations I see.
>> >
>> > The first is where the enum is a flag or comibation of flags which is used to
>> > pass multiple booleans /small integers efficiently.
>> I would not call that an enum.
>> > The second is where the enum is a collection of labels which defines a set,
>> > but where there is no paticular mathematical relationship. For example
>> > amino acids in proteins.
>> Again, I'd not call that an enum. enum implies enumeration so there
>> should be a successor and predecessor operation.
>> > The third is where you have a relationship such that the members are ordered.
>> > This might be a natural order (BABY, TODDLER, CHILD, TEENAGER, YOUTH,
>> > MIDDLEAGED, PENSIONER), or it might be a strong social convention (A,
>> > B, C ...).
>> This one is an enum!
>>
>> If I were making it up from a blank slate, I'd have collections of
>> symbols which might or might not be ordered:
>>
>> NAMES { verbose, logging, no_splash } flags;
>> SET OF flags options;
>>
>> /* succ(verbose) not defined but name_of(verbose) == "verbose" */
>>
>> ORDERED NAMES { GCSE, A_Level, Degree, Postgraduate } qualifications;
>>
>> /* succ(GCSE) == A_Level and ord(Degree) == 2 */
>> > The other logical situation is an ordering, with the added stipulation
>> > that the intervals be the same. I suggest that an enum is not suitable
>> > for this kind of data.
>> Except, presumably, when the interval is 1? That's almost the textbook
>> definition of an enumeration.
>>
> The elements are an example. Hydrogen has one proton, Helium two,
> Lithium three, and it goes up in steps of one proton. However the end
> of the table is a bit fuzzy. Whilst not claiming to be a physicist, I don't
> think we yet understand whether there is hard limit on how many protons
> can fuse into a single atom or not. So there's an argument for using an integer
> count of protons instead of an enum to represent elements.
I don't think this is a good use of an enumerated type (and I think you
agree but I'm just checking). An ordered set of names has the usual
partial successor and predecessor function which imply and ordinal
number (so you might as well have that too) but the values themselves
have no meaning.
While I am at it, maybe one should be able to specify a cyclic order for
things like days of the week. There would still be succ and pred
functions but they would now be total functions so they do not induce an
ord function.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2021-10-01 15:12 -0700 |
| Message-ID | <11b64ac2-d760-44e4-a1f5-605c0b7e59a3n@googlegroups.com> |
| In reply to | #162908 |
On Friday, 1 October 2021 at 17:09:11 UTC+1, Ben Bacarisse wrote:
> Malcolm McLean <malcolm.ar...@gmail.com> writes:
>
> > On Friday, 1 October 2021 at 15:30:38 UTC+1, Ben Bacarisse wrote:
> >> Malcolm McLean <malcolm.ar...@gmail.com> writes:
> >>
> >> > There are three distinct situations I see.
> >> >
> >> > The first is where the enum is a flag or comibation of flags which is used to
> >> > pass multiple booleans /small integers efficiently.
> >> I would not call that an enum.
> >> > The second is where the enum is a collection of labels which defines a set,
> >> > but where there is no paticular mathematical relationship. For example
> >> > amino acids in proteins.
> >> Again, I'd not call that an enum. enum implies enumeration so there
> >> should be a successor and predecessor operation.
> >> > The third is where you have a relationship such that the members are ordered.
> >> > This might be a natural order (BABY, TODDLER, CHILD, TEENAGER, YOUTH,
> >> > MIDDLEAGED, PENSIONER), or it might be a strong social convention (A,
> >> > B, C ...).
> >> This one is an enum!
> >>
> >> If I were making it up from a blank slate, I'd have collections of
> >> symbols which might or might not be ordered:
> >>
> >> NAMES { verbose, logging, no_splash } flags;
> >> SET OF flags options;
> >>
> >> /* succ(verbose) not defined but name_of(verbose) == "verbose" */
> >>
> >> ORDERED NAMES { GCSE, A_Level, Degree, Postgraduate } qualifications;
> >>
> >> /* succ(GCSE) == A_Level and ord(Degree) == 2 */
> >> > The other logical situation is an ordering, with the added stipulation
> >> > that the intervals be the same. I suggest that an enum is not suitable
> >> > for this kind of data.
> >> Except, presumably, when the interval is 1? That's almost the textbook
> >> definition of an enumeration.
> >>
> > The elements are an example. Hydrogen has one proton, Helium two,
> > Lithium three, and it goes up in steps of one proton. However the end
> > of the table is a bit fuzzy. Whilst not claiming to be a physicist, I don't
> > think we yet understand whether there is hard limit on how many protons
> > can fuse into a single atom or not. So there's an argument for using an integer
> > count of protons instead of an enum to represent elements.
> I don't think this is a good use of an enumerated type (and I think you
> agree but I'm just checking). An ordered set of names has the usual
> partial successor and predecessor function which imply and ordinal
> number (so you might as well have that too) but the values themselves
> have no meaning.
>
Amino acids used to have three letter identifiers. Now they have one-letter
identifiers. Largely because of the needs of computers. So it's natural to
pass them about as acii values. There are also twenty of them, so a 26-entry
table with a few gaps isn't too extravagant a waste of memory.
The disadvantage is that a beginner biochemist can easily see that Trp
means "Tryptophan", for example, but he'll only know what "W" means if he
has committed the symbols to memory.
Unfortunately there are about a hundred elements, so you run out of letters,
and most elements have two character symbols. That's far less convenient
for a language like C which isn't set up do operations on short strings.
So the case for an element enum is stronger than for amino acids. Hydrogen
would have to have the value 1 and not 0 - the alternative would be crazy.
However an enum isn't ideal. Unless you are doing particle physics, the number
of protons in an atom isn't really interesting - characteristics like valency
and the radius of its ions are what determine the chemical characteristics.
And normally you'll be working with a very small subset of the elements.
>
> While I am at it, maybe one should be able to specify a cyclic order for
> things like days of the week. There would still be succ and pred
> functions but they would now be total functions so they do not induce an
> ord function.
>
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-10-01 15:37 +0200 |
| Message-ID | <sj72vg$5l7$1@dont-email.me> |
| In reply to | #162893 |
On 01/10/2021 14:06, Bart wrote:
> On 01/10/2021 12:49, Malcolm McLean wrote:
>> On Friday, 1 October 2021 at 11:24:29 UTC+1, Bart wrote:
>>> On 01/10/2021 08:20, David Brown wrote:
>>>> On 30/09/2021 16:36, Malcolm McLean wrote:
>>>>> On Thursday, 30 September 2021 at 11:45:50 UTC+1, David Brown wrote:
>>>>>>
>>>>>> But I think that in most cases, it is not at all helpful to think
>>>>>> about
>>>>>> the underlying integer values. You get cleaner, safer, more portable
>>>>>> code if you treat the enumeration constants as being abstract symbols
>>>>>> that are members of the particular type without any other
>>>>>> semantics or
>>>>>> meaning.
>>>>>>
>>>>> I agree, but there are some snags. One is if you wish to print out
>>>>> the enum
>>>>> for debug purposes. It's easy enough to write printf("light %d\n",
>>>>> (int) lightenumval);
>>>>> If you have to set up an enum to string function then it's a bit
>>>>> clearer, but it's a huge
>>>>> hassle for debug.
>>>>> The other snag is that often you want to use the enum to index into
>>>>> a table
>>>>> of some sort. Again, you can set up a system by writing a switch,
>>>>> but that's
>>>>> likely slower and more code.
>>>>>
>>>>
>>>> These are not "snags" - they are cases where the underlying integer
>>>> value of the enumeration constants is sometimes helpful due to the
>>>> limitations of the language. Eventually, C++ will get some decent
>>>> compile-time reflection capabilities that will allow you to generate
>>>> strings from enumeration constants simply and easily, without
>>>> repetition
>>>> in the code (and without complicated X-macros).
>>>>
>>>> In the meantime, C99, and C++ with gcc extensions (unfortunately not
>>>> standard), let you write:
>>>>
>>>>
>>>> typedef enum Colours { red, green, blue } Colours;
>>>>
>>>> extern const char * const colour_names[];
>>>> const char * const colour_names[] = {
>>>> [red] = "red",
>>>> [green] = "green",
>>>> [blue] = "blue",
>>>> };
>>> This is not ideal:
>>>
>> For some purposes you really need a special function called something
>> like "enum_to_string",
>> as David Brown implied. Then const char *name = enum_to_string(red),
>> sets name to "red".
>> That would be good for debug messages,
>>
>> printf("Car crashed lights were %s\n", enum_to_string( lightvalue));
>>
>> maybe you could also use it in a database
>>
>> struct crashrecord
>> {
>> double speed;
>> bool aidrivingon;
>> char lasttrafficlights[8]; // red, amber, green
>> };
>>
>> However it wouldn't normally be acceptable for user-facing strings.
>>
>> To implement, you would need enums to be types, then enum_to_string
>> would be a bit like
>> "sizeof", a function (maths sense) which isn't a subroutine but a
>> keyword.
>>
>
> It would need a bit more than that. At the moment, C allows:
>
> enum { red=1, green=1, blue=1 };
>
> enum { red=1000000000, green=2000000000, blue=-2000000000 };
>
You apparently missed the topic of this thread branch. We are looking
at enumerations where the underlying integer constants are neither
specified nor used - we are looking at ways to treat them as higher
level, purely symbolic identifiers.
No language will help programmers who ignore the task in hand, skip the
conventions in use at the time, and write intentionally idiotic code.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 15:30 +0100 |
| Message-ID | <sj761r$pom$1@dont-email.me> |
| In reply to | #162901 |
On 01/10/2021 14:37, David Brown wrote:
> On 01/10/2021 14:06, Bart wrote:
>> On 01/10/2021 12:49, Malcolm McLean wrote:
>>> On Friday, 1 October 2021 at 11:24:29 UTC+1, Bart wrote:
>>>> On 01/10/2021 08:20, David Brown wrote:
>>>>> On 30/09/2021 16:36, Malcolm McLean wrote:
>>>>>> On Thursday, 30 September 2021 at 11:45:50 UTC+1, David Brown wrote:
>>>>>>>
>>>>>>> But I think that in most cases, it is not at all helpful to think
>>>>>>> about
>>>>>>> the underlying integer values. You get cleaner, safer, more portable
>>>>>>> code if you treat the enumeration constants as being abstract symbols
>>>>>>> that are members of the particular type without any other
>>>>>>> semantics or
>>>>>>> meaning.
>>>>>>>
>>>>>> I agree, but there are some snags. One is if you wish to print out
>>>>>> the enum
>>>>>> for debug purposes. It's easy enough to write printf("light %d\n",
>>>>>> (int) lightenumval);
>>>>>> If you have to set up an enum to string function then it's a bit
>>>>>> clearer, but it's a huge
>>>>>> hassle for debug.
>>>>>> The other snag is that often you want to use the enum to index into
>>>>>> a table
>>>>>> of some sort. Again, you can set up a system by writing a switch,
>>>>>> but that's
>>>>>> likely slower and more code.
>>>>>>
>>>>>
>>>>> These are not "snags" - they are cases where the underlying integer
>>>>> value of the enumeration constants is sometimes helpful due to the
>>>>> limitations of the language. Eventually, C++ will get some decent
>>>>> compile-time reflection capabilities that will allow you to generate
>>>>> strings from enumeration constants simply and easily, without
>>>>> repetition
>>>>> in the code (and without complicated X-macros).
>>>>>
>>>>> In the meantime, C99, and C++ with gcc extensions (unfortunately not
>>>>> standard), let you write:
>>>>>
>>>>>
>>>>> typedef enum Colours { red, green, blue } Colours;
>>>>>
>>>>> extern const char * const colour_names[];
>>>>> const char * const colour_names[] = {
>>>>> [red] = "red",
>>>>> [green] = "green",
>>>>> [blue] = "blue",
>>>>> };
>>>> This is not ideal:
>>>>
>>> For some purposes you really need a special function called something
>>> like "enum_to_string",
>>> as David Brown implied. Then const char *name = enum_to_string(red),
>>> sets name to "red".
>>> That would be good for debug messages,
>>>
>>> printf("Car crashed lights were %s\n", enum_to_string( lightvalue));
>>>
>>> maybe you could also use it in a database
>>>
>>> struct crashrecord
>>> {
>>> double speed;
>>> bool aidrivingon;
>>> char lasttrafficlights[8]; // red, amber, green
>>> };
>>>
>>> However it wouldn't normally be acceptable for user-facing strings.
>>>
>>> To implement, you would need enums to be types, then enum_to_string
>>> would be a bit like
>>> "sizeof", a function (maths sense) which isn't a subroutine but a
>>> keyword.
>>>
>>
>> It would need a bit more than that. At the moment, C allows:
>>
>> enum { red=1, green=1, blue=1 };
>>
>> enum { red=1000000000, green=2000000000, blue=-2000000000 };
>>
>
> You apparently missed the topic of this thread branch. We are looking
> at enumerations where the underlying integer constants are neither
> specified nor used - we are looking at ways to treat them as higher
> level, purely symbolic identifiers.
And you missed my point: currently enum stills allows those enums with
arbitrary, unrelated values.
If you're to turn runtime instances of such values into strings, that
will cause difficultiies.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-10-01 19:12 +0200 |
| Message-ID | <sj7fhv$c37$1@dont-email.me> |
| In reply to | #162902 |
On 01/10/2021 16:30, Bart wrote:
> On 01/10/2021 14:37, David Brown wrote:
>> On 01/10/2021 14:06, Bart wrote:
>>> On 01/10/2021 12:49, Malcolm McLean wrote:
>>>> On Friday, 1 October 2021 at 11:24:29 UTC+1, Bart wrote:
>>>>> On 01/10/2021 08:20, David Brown wrote:
>>>>>> On 30/09/2021 16:36, Malcolm McLean wrote:
>>>>>>> On Thursday, 30 September 2021 at 11:45:50 UTC+1, David Brown wrote:
>>>>>>>>
>>>>>>>> But I think that in most cases, it is not at all helpful to think
>>>>>>>> about
>>>>>>>> the underlying integer values. You get cleaner, safer, more
>>>>>>>> portable
>>>>>>>> code if you treat the enumeration constants as being abstract
>>>>>>>> symbols
>>>>>>>> that are members of the particular type without any other
>>>>>>>> semantics or
>>>>>>>> meaning.
>>>>>>>>
>>>>>>> I agree, but there are some snags. One is if you wish to print out
>>>>>>> the enum
>>>>>>> for debug purposes. It's easy enough to write printf("light %d\n",
>>>>>>> (int) lightenumval);
>>>>>>> If you have to set up an enum to string function then it's a bit
>>>>>>> clearer, but it's a huge
>>>>>>> hassle for debug.
>>>>>>> The other snag is that often you want to use the enum to index into
>>>>>>> a table
>>>>>>> of some sort. Again, you can set up a system by writing a switch,
>>>>>>> but that's
>>>>>>> likely slower and more code.
>>>>>>>
>>>>>>
>>>>>> These are not "snags" - they are cases where the underlying integer
>>>>>> value of the enumeration constants is sometimes helpful due to the
>>>>>> limitations of the language. Eventually, C++ will get some decent
>>>>>> compile-time reflection capabilities that will allow you to generate
>>>>>> strings from enumeration constants simply and easily, without
>>>>>> repetition
>>>>>> in the code (and without complicated X-macros).
>>>>>>
>>>>>> In the meantime, C99, and C++ with gcc extensions (unfortunately not
>>>>>> standard), let you write:
>>>>>>
>>>>>>
>>>>>> typedef enum Colours { red, green, blue } Colours;
>>>>>>
>>>>>> extern const char * const colour_names[];
>>>>>> const char * const colour_names[] = {
>>>>>> [red] = "red",
>>>>>> [green] = "green",
>>>>>> [blue] = "blue",
>>>>>> };
>>>>> This is not ideal:
>>>>>
>>>> For some purposes you really need a special function called something
>>>> like "enum_to_string",
>>>> as David Brown implied. Then const char *name = enum_to_string(red),
>>>> sets name to "red".
>>>> That would be good for debug messages,
>>>>
>>>> printf("Car crashed lights were %s\n", enum_to_string( lightvalue));
>>>>
>>>> maybe you could also use it in a database
>>>>
>>>> struct crashrecord
>>>> {
>>>> double speed;
>>>> bool aidrivingon;
>>>> char lasttrafficlights[8]; // red, amber, green
>>>> };
>>>>
>>>> However it wouldn't normally be acceptable for user-facing strings.
>>>>
>>>> To implement, you would need enums to be types, then enum_to_string
>>>> would be a bit like
>>>> "sizeof", a function (maths sense) which isn't a subroutine but a
>>>> keyword.
>>>>
>>>
>>> It would need a bit more than that. At the moment, C allows:
>>>
>>> enum { red=1, green=1, blue=1 };
>>>
>>> enum { red=1000000000, green=2000000000, blue=-2000000000 };
>>>
>>
>> You apparently missed the topic of this thread branch. We are looking
>> at enumerations where the underlying integer constants are neither
>> specified nor used - we are looking at ways to treat them as higher
>> level, purely symbolic identifiers.
>
> And you missed my point: currently enum stills allows those enums with
> arbitrary, unrelated values.
>
> If you're to turn runtime instances of such values into strings, that
> will cause difficultiies.
And most programming languages or tools allow identifiers made from a
permutation of a hundred letters "O" and "I", which will cause
difficulties when writing code or debugging. So what? The "enum" in C
lets you use arbitrary unrelated integer values. So what? None of that
is remotely relevant to the topic at hand. We are looking at how to
work with enumerations without considering their underlying integer values.
If you want to hijack threads to repeat how you hate C because it can be
abused by the malicious or the moronic, and claim that /your/ language
is therefore better, please consider changing the subject of the post.
Then we'll all know that you are going off on another anti-C tangent.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 19:06 +0100 |
| Message-ID | <sj7in2$6nb$1@dont-email.me> |
| In reply to | #162911 |
On 01/10/2021 18:12, David Brown wrote: > On 01/10/2021 16:30, Bart wrote: >> On 01/10/2021 14:37, David Brown wrote: >>> You apparently missed the topic of this thread branch. We are looking >>> at enumerations where the underlying integer constants are neither >>> specified nor used - we are looking at ways to treat them as higher >>> level, purely symbolic identifiers. >> >> And you missed my point: currently enum stills allows those enums with >> arbitrary, unrelated values. >> >> If you're to turn runtime instances of such values into strings, that >> will cause difficultiies. > > And most programming languages or tools allow identifiers made from a > permutation of a hundred letters "O" and "I", which will cause > difficulties when writing code or debugging. So what? The "enum" in C > lets you use arbitrary unrelated integer values. So what? None of that > is remotely relevant to the topic at hand. We are looking at how to > work with enumerations without considering their underlying integer values. The topic I was responding to was about turning an enum value stored in an int, into a string representing its name. That's difficult to do in C. It's difficult to do my language (neither have sophisticated enough type systems), even when the enum values are consecutive, which is the only type I'm interested it. But I mentioned a couple of approaches which simplifies the process of writing and maintaining the necessary data. One I started off using outside my language and eventually made it built-in. That first method can still be used in C. It still requires, like your suggestion, some extra input from the programmer: the name of the array of names, since otherwise there is just a generic int value. The programmer has to know what enum type is stored. I haven't attacked C this time, other than its too-flexible enums make it harder to solve. I mildly attacked your solution by highlighting the shortcomings. And I attacked x-macros.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-10-01 15:32 +0200 |
| Message-ID | <sj72lq$3f2$1@dont-email.me> |
| In reply to | #162891 |
On 01/10/2021 12:24, Bart wrote:
> On 01/10/2021 08:20, David Brown wrote:
>> On 30/09/2021 16:36, Malcolm McLean wrote:
>>> On Thursday, 30 September 2021 at 11:45:50 UTC+1, David Brown wrote:
>>>>
>>>> But I think that in most cases, it is not at all helpful to think about
>>>> the underlying integer values. You get cleaner, safer, more portable
>>>> code if you treat the enumeration constants as being abstract symbols
>>>> that are members of the particular type without any other semantics or
>>>> meaning.
>>>>
>>> I agree, but there are some snags. One is if you wish to print out
>>> the enum
>>> for debug purposes. It's easy enough to write printf("light %d\n",
>>> (int) lightenumval);
>>> If you have to set up an enum to string function then it's a bit
>>> clearer, but it's a huge
>>> hassle for debug.
>>> The other snag is that often you want to use the enum to index into a
>>> table
>>> of some sort. Again, you can set up a system by writing a switch, but
>>> that's
>>> likely slower and more code.
>>>
>>
>> These are not "snags" - they are cases where the underlying integer
>> value of the enumeration constants is sometimes helpful due to the
>> limitations of the language. Eventually, C++ will get some decent
>> compile-time reflection capabilities that will allow you to generate
>> strings from enumeration constants simply and easily, without repetition
>> in the code (and without complicated X-macros).
>>
>> In the meantime, C99, and C++ with gcc extensions (unfortunately not
>> standard), let you write:
>>
>>
>> typedef enum Colours { red, green, blue } Colours;
>>
>> extern const char * const colour_names[];
>> const char * const colour_names[] = {
>> [red] = "red",
>> [green] = "green",
>> [blue] = "blue",
>> };
>
> This is not ideal:
>
Obviously it is not ideal - that was clearly implied by what I wrote.
And we don't need a list of the weaknesses here, and we certainly do not
need another useless example from your personal language. If you want
to suggest improvements in C (or C++, though that is less topical here),
that would be marvellous.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 15:38 +0100 |
| Message-ID | <sj76ho$io$1@dont-email.me> |
| In reply to | #162900 |
On 01/10/2021 14:32, David Brown wrote:
> On 01/10/2021 12:24, Bart wrote:
>> On 01/10/2021 08:20, David Brown wrote:
>>> On 30/09/2021 16:36, Malcolm McLean wrote:
>>>> On Thursday, 30 September 2021 at 11:45:50 UTC+1, David Brown wrote:
>>>>>
>>>>> But I think that in most cases, it is not at all helpful to think about
>>>>> the underlying integer values. You get cleaner, safer, more portable
>>>>> code if you treat the enumeration constants as being abstract symbols
>>>>> that are members of the particular type without any other semantics or
>>>>> meaning.
>>>>>
>>>> I agree, but there are some snags. One is if you wish to print out
>>>> the enum
>>>> for debug purposes. It's easy enough to write printf("light %d\n",
>>>> (int) lightenumval);
>>>> If you have to set up an enum to string function then it's a bit
>>>> clearer, but it's a huge
>>>> hassle for debug.
>>>> The other snag is that often you want to use the enum to index into a
>>>> table
>>>> of some sort. Again, you can set up a system by writing a switch, but
>>>> that's
>>>> likely slower and more code.
>>>>
>>>
>>> These are not "snags" - they are cases where the underlying integer
>>> value of the enumeration constants is sometimes helpful due to the
>>> limitations of the language. Eventually, C++ will get some decent
>>> compile-time reflection capabilities that will allow you to generate
>>> strings from enumeration constants simply and easily, without repetition
>>> in the code (and without complicated X-macros).
>>>
>>> In the meantime, C99, and C++ with gcc extensions (unfortunately not
>>> standard), let you write:
>>>
>>>
>>> typedef enum Colours { red, green, blue } Colours;
>>>
>>> extern const char * const colour_names[];
>>> const char * const colour_names[] = {
>>> [red] = "red",
>>> [green] = "green",
>>> [blue] = "blue",
>>> };
>>
>> This is not ideal:
>>
> Obviously it is not ideal - that was clearly implied by what I wrote.
> And we don't need a list of the weaknesses here,
Why not? I listed most of the problems, which may not have been
apparently to everyone since your example was written perfectly, and
showed how I get around most of those with a unique approach of mine, a
feature I now find invaluable.
I'm not making a proposal for C; it's an idea that someone else could
pick up on and maybe suggest or implement something better than those
ghastly X-macros.
You're welcome.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 17:40 +0100 |
| Message-ID | <sj7dmk$rbe$1@dont-email.me> |
| In reply to | #162904 |
On 01/10/2021 15:38, Bart wrote:
> On 01/10/2021 14:32, David Brown wrote:
>> On 01/10/2021 12:24, Bart wrote:
>>> On 01/10/2021 08:20, David Brown wrote:
>>>> On 30/09/2021 16:36, Malcolm McLean wrote:
>>>>> On Thursday, 30 September 2021 at 11:45:50 UTC+1, David Brown wrote:
>>>>>>
>>>>>> But I think that in most cases, it is not at all helpful to think
>>>>>> about
>>>>>> the underlying integer values. You get cleaner, safer, more portable
>>>>>> code if you treat the enumeration constants as being abstract symbols
>>>>>> that are members of the particular type without any other
>>>>>> semantics or
>>>>>> meaning.
>>>>>>
>>>>> I agree, but there are some snags. One is if you wish to print out
>>>>> the enum
>>>>> for debug purposes. It's easy enough to write printf("light %d\n",
>>>>> (int) lightenumval);
>>>>> If you have to set up an enum to string function then it's a bit
>>>>> clearer, but it's a huge
>>>>> hassle for debug.
>>>>> The other snag is that often you want to use the enum to index into a
>>>>> table
>>>>> of some sort. Again, you can set up a system by writing a switch, but
>>>>> that's
>>>>> likely slower and more code.
>>>>>
>>>>
>>>> These are not "snags" - they are cases where the underlying integer
>>>> value of the enumeration constants is sometimes helpful due to the
>>>> limitations of the language. Eventually, C++ will get some decent
>>>> compile-time reflection capabilities that will allow you to generate
>>>> strings from enumeration constants simply and easily, without
>>>> repetition
>>>> in the code (and without complicated X-macros).
>>>>
>>>> In the meantime, C99, and C++ with gcc extensions (unfortunately not
>>>> standard), let you write:
>>>>
>>>>
>>>> typedef enum Colours { red, green, blue } Colours;
>>>>
>>>> extern const char * const colour_names[];
>>>> const char * const colour_names[] = {
>>>> [red] = "red",
>>>> [green] = "green",
>>>> [blue] = "blue",
>>>> };
>>>
>>> This is not ideal:
>>>
>> Obviously it is not ideal - that was clearly implied by what I wrote.
>> And we don't need a list of the weaknesses here,
>
> Why not? I listed most of the problems, which may not have been
> apparently to everyone since your example was written perfectly, and
> showed how I get around most of those with a unique approach of mine, a
> feature I now find invaluable.
>
> I'm not making a proposal for C; it's an idea that someone else could
> pick up on and maybe suggest or implement something better than those
> ghastly X-macros.
>
> You're welcome.
>
BTW, before I had that feature built-in to my language, I used external
scripts to generate it from tables written as .tab files.
I had a script to turn .tab files into my syntax, but there was also one
to turn it into C syntax (both a .h and .c file were generated). The
last version of that was from 2008.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-02 12:16 +0100 |
| Message-ID | <sj9f3d$4v1$1@dont-email.me> |
| In reply to | #162891 |
On 01/10/2021 11:24, Bart wrote:
> On 01/10/2021 08:20, David Brown wrote:
>> typedef enum Colours { red, green, blue } Colours;
>>
>> extern const char * const colour_names[];
>> const char * const colour_names[] = {
>> [red] = "red",
>> [green] = "green",
>> [blue] = "blue",
>> };
>
> However I do use this feature:
>
> tabledata() []ichar colour_names =
> (red, $),
> (green, $),
> (blue, $),
> end
I know this will intensely annoy David Brown, so I suggest he doesn't
read further.
Below is a real example of such a set of enums from some old project of
mine.
Here's a C X-macro version for comparison, partly populated:
#define COLOURTABLE \
COL(black, 00,00,00) \
COL(red, 00,00,C0) \
COL(white, FF,FF,FF) \
enum colours {
#define COL(name,b,g,r) \
name,
COLOURTABLE
#undef COL
};
char* coloursnames[] = {
#define COL(name,b,g,r) \
#name,
COLOURTABLE
#undef COL
};
unsigned int coloursvalues[] = {
#define COL(name,b,g,r) \
0x##b##g##r,
COLOURTABLE
#undef COL
};
Lovely. However, while my version below is automatically visible to all
modules that bother to import this one, the C requires some extra
hackery to share it across modules.
-----------------------------------------
global tabledata() colournames, colourvalues =
! BB'GG'RR
(black, $, 0x_00'00'00),
(red, $, 0x_00'00'C0),
(dkred, $, 0x_00'00'90),
(red3, $, 0x_00'00'70),
(green, $, 0x_00'C0'00),
(dkgreen, $, 0x_00'90'00),
(green3, $, 0x_00'70'00),
(blue, $, 0x_C0'00'00),
(dkblue, $, 0x_90'00'00),
(blue3, $, 0x_70'00'00),
(cyan, $, 0x_c0'c0'00),
(dkcyan, $, 0x_90'90'00),
(cyan3, $, 0x_70'70'00),
(magenta, $, 0x_c0'00'c0),
(dkmagenta, $, 0x_90'00'90),
(magenta3, $, 0x_70'00'70),
(yellow, $, 0x_00'C0'C0),
(dkyellow, $, 0x_00'90'90),
(yellow3, $, 0x_00'70'70),
(yellow4, $, 0x_00'50'50),
(white, $, 0x_FF'FF'FF),
(ltgrey, $, 0x_C0'C0'C0),
(grey, $, 0x_90'90'90),
(dkgrey, $, 0x_70'70'70),
....
end
(Example is from dynamic code. Static code would be identical, except
that types are needed:
global tabledata() []ichar colournames, []ichar colourvalues =
)
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-10-02 15:34 +0200 |
| Message-ID | <sj9n4r$ob9$1@dont-email.me> |
| In reply to | #162934 |
On 02/10/2021 13:16, Bart wrote:
> On 01/10/2021 11:24, Bart wrote:
>> On 01/10/2021 08:20, David Brown wrote:
>
>>> typedef enum Colours { red, green, blue } Colours;
>>>
>>> extern const char * const colour_names[];
>>> const char * const colour_names[] = {
>>> [red] = "red",
>>> [green] = "green",
>>> [blue] = "blue",
>>> };
>>
>
>> However I do use this feature:
>>
>> tabledata() []ichar colour_names =
>> (red, $),
>> (green, $),
>> (blue, $),
>> end
>
> I know this will intensely annoy David Brown, so I suggest he doesn't
> read further.
>
> Below is a real example of such a set of enums from some old project of
> mine.
>
> Here's a C X-macro version for comparison, partly populated:
>
> #define COLOURTABLE \
> COL(black, 00,00,00) \
> COL(red, 00,00,C0) \
> COL(white, FF,FF,FF) \
>
>
> enum colours {
> #define COL(name,b,g,r) \
> name,
> COLOURTABLE
> #undef COL
> };
>
> char* coloursnames[] = {
> #define COL(name,b,g,r) \
> #name,
> COLOURTABLE
> #undef COL
> };
>
> unsigned int coloursvalues[] = {
> #define COL(name,b,g,r) \
> 0x##b##g##r,
> COLOURTABLE
> #undef COL
> };
>
>
> Lovely.
X-macros are a bit ugly, and I'd prefer if the language (C or C++)
supported a way to avoid repetition here without using them. But they
can be done in a good deal neater manner than this. If you are
interested, look here:
<https://www.codeproject.com/Articles/1118009/A-Smart-Enum-library-in-C-using-X-macros>
> However, while my version below is automatically visible to all
> modules that bother to import this one, the C requires some extra
> hackery to share it across modules.
>
It needs no extra hackery for that. Your declarations go in the header,
definitions go in the C implementation file - as usual. (If you are
using C++, it can all go in the header if you prefer - these days, there
is no need for separate implementation files for things like this.)
> -----------------------------------------
>
> global tabledata() colournames, colourvalues =
> ! BB'GG'RR
> (black, $, 0x_00'00'00),
>
> (red, $, 0x_00'00'C0),
> (dkred, $, 0x_00'00'90),
> (red3, $, 0x_00'00'70),
>
> (green, $, 0x_00'C0'00),
> (dkgreen, $, 0x_00'90'00),
> (green3, $, 0x_00'70'00),
>
> (blue, $, 0x_C0'00'00),
> (dkblue, $, 0x_90'00'00),
> (blue3, $, 0x_70'00'00),
>
> (cyan, $, 0x_c0'c0'00),
> (dkcyan, $, 0x_90'90'00),
> (cyan3, $, 0x_70'70'00),
>
> (magenta, $, 0x_c0'00'c0),
> (dkmagenta, $, 0x_90'00'90),
> (magenta3, $, 0x_70'00'70),
>
> (yellow, $, 0x_00'C0'C0),
> (dkyellow, $, 0x_00'90'90),
> (yellow3, $, 0x_00'70'70),
> (yellow4, $, 0x_00'50'50),
>
> (white, $, 0x_FF'FF'FF),
> (ltgrey, $, 0x_C0'C0'C0),
> (grey, $, 0x_90'90'90),
> (dkgrey, $, 0x_70'70'70),
>
> ....
> end
>
> (Example is from dynamic code. Static code would be identical, except
> that types are needed:
>
> global tabledata() []ichar colournames, []ichar colourvalues =
>
> )
The dollar sign is a bit odd. A typical X-macro usage would have a list
like:
_(black, 0x000000),
_(red, 0x0000C0),
which is a bit neater. (Spacing is personal preference, and digital
separators need C++ or must wait for C23.)
It's nice that you don't need the boilerplate of X-macros.
Does your language also have built-in support for things like first,
last, successor, etc., for enumerations? What about generation of
functions back and forth between strings and enumerators?
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-02 15:16 +0100 |
| Message-ID | <sj9pjl$am6$1@dont-email.me> |
| In reply to | #162935 |
On 02/10/2021 14:34, David Brown wrote:
> On 02/10/2021 13:16, Bart wrote:
>> Here's a C X-macro version for comparison, partly populated:
>>
>> #define COLOURTABLE \
>> COL(black, 00,00,00) \
>> COL(red, 00,00,C0) \
>> COL(white, FF,FF,FF) \
>>
>>
>> enum colours {
>> #define COL(name,b,g,r) \
>> name,
>> COLOURTABLE
>> #undef COL
>> };
>>
>> char* coloursnames[] = {
>> #define COL(name,b,g,r) \
>> #name,
>> COLOURTABLE
>> #undef COL
>> };
>>
>> unsigned int coloursvalues[] = {
>> #define COL(name,b,g,r) \
>> 0x##b##g##r,
>> COLOURTABLE
>> #undef COL
>> };
>> However, while my version below is automatically visible to all
>> modules that bother to import this one, the C requires some extra
>> hackery to share it across modules.
>>
>
> It needs no extra hackery for that. Your declarations go in the header,
> definitions go in the C implementation file - as usual.
That's what I meant really: the main #define with the table, and the
enum definitions, go in the header. Also in the header go declarations
for those parallel arrays. But the definitions for them need to go in a
suitable .c file.
In all 5 extra lots of stuff compared with the main table. When I used
to do this via external scripts, the one for C generated a suitable .h
and .c file for the two parts, normally included in bigger files.
>> -----------------------------------------
>>
>> global tabledata() colournames, colourvalues =
>> ! BB'GG'RR
>> (black, $, 0x_00'00'00),
> The dollar sign is a bit odd.
It's a gimmick. $ turns the last defined enum name into a string
literal. Probably this could be eliminated (so a list of names - given a
enum identity that goes in "()" - is automaticaly generated). But this
works well enough.
Sometimes you want a set of strings, or some of them, that vary
significantly from the enum names in the source code, eg. not just skip
some prefix, then you replace $ with an actual string.
_ A typical X-macro usage would have a list
> like:
>
> _(black, 0x000000),
> _(red, 0x0000C0),
>
> which is a bit neater. (Spacing is personal preference, and digital
> separators need C++ or must wait for C23.)
>
> It's nice that you don't need the boilerplate of X-macros.
>
> Does your language also have built-in support for things like first,
> last, successor, etc., for enumerations?
No, it's very crude. If parallel arrays have been defined like my
example, then colournames.lwb gives the first enum value, and
colournames.upb gives the last.
(For the X-macro version, the first value is 0, and the last needs the
usual sizeof method.)
++ and -- (or +1 and -1) step between them.
You can iterate over the values using 'for i in colournames.bounds'.
But often I just provide an explicit sentinel to mark the end.
> What about generation of
> functions back and forth between strings and enumerators?
Not sure what you mean here. In dynamic code, then:
s := "red"
s in colournames
yields 2 (when 1-based), which is the same value as red.
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | comp.lang.c
csiph-web