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 1 of 3 [1] 2 3 Next page →
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2021-09-27 10:39 -0700 |
| Subject | redeclaration of enumerators? |
| Message-ID | <a81bc0a9-beb2-4ec9-9c07-d1a3985b746an@googlegroups.com> |
I was wondering if we have some reason to
disallow redeclaration of identical (name/value) enumerators.
enum E1 { A = 1 };
enum E2 { A = 1 };
The enum type in this case could be used to indicate the
set type while the enumerators are just constant of type int
that can be converted to enum set.
The type of the constant that is ambiguous it can be E1 or E2.
maybe this is the problem...
But we already have a problem today:
#include <stdio.h>
enum E1 {
A = 1
};
#define typename(x) \
_Generic((x),\
unsigned int: "int",\
enum E1 : "enum E1", \
default: "other")
int main() {
printf("%s %s", typename(A), typename(1));
}
this is the gcc error
error: '_Generic' specifies two compatible types
this compiles:
#include <stdio.h>
enum E1 { A1 = 1 };
enum E2 { A2 = 1 };
#define typename(x) \
_Generic((x),\
enum E1 : "enum E1", \
enum E2 : "enum E2", \
default: "other")
int main() {
printf("%s %s", typename(A1), typename(A2));
}
and it prints
other other
---
(changing to)
#define typename(x) \
_Generic((x),\
enum E1 : "enum E1", \
int : "int", \
default: "other")
prints
int int
[toc] | [next] | [standalone]
| From | John Bode <jfbode1029@gmail.com> |
|---|---|
| Date | 2021-09-28 16:21 -0500 |
| Message-ID | <sj010b$715$1@dont-email.me> |
| In reply to | #162848 |
On 9/27/21 12:39 PM, Thiago Adams wrote:
> I was wondering if we have some reason to
> disallow redeclaration of identical (name/value) enumerators.
>
> enum E1 { A = 1 };
> enum E2 { A = 1 };
>
Unlike structs and unions, each enum type is not its own
namespace and enumeration constants belong to the "ordinary
identifiers" namespace.
The question is how you would disambiguate the two definitions
of A - there's no equivalent to the '.' or '->' operators for
enums. There's no way to easily say "I'm talking about the A
defined for enum E1, not the A defined for enum E2".
Can't rely on type inference in assignments; enums are just an
incredibly weak abstraction in C. There's no range checking
such that you can only assign one of the defined enumeration
constants to an object of that enum type.
You'd either need to introduce a C++-style scoping operator like
E1::A or E2::A, or you'd need to radically revamp and strengthen
enum semantics. And in the process you'd likely lose some capability
that people find incredibly useful, such as bitwise-ORing enumeration
constants together.
enums in C are little more than a way to create symbolic constants for
integer values. They are not really *enumerated types* like you
find in other languages.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2021-09-28 14:57 -0700 |
| Message-ID | <8735pojrc3.fsf@nosuchdomain.example.com> |
| In reply to | #162859 |
John Bode <jfbode1029@gmail.com> writes:
> On 9/27/21 12:39 PM, Thiago Adams wrote:
>> I was wondering if we have some reason to
>> disallow redeclaration of identical (name/value) enumerators.
>> enum E1 { A = 1 };
>> enum E2 { A = 1 };
>
> Unlike structs and unions, each enum type is not its own
> namespace and enumeration constants belong to the "ordinary
> identifiers" namespace.
>
> The question is how you would disambiguate the two definitions
> of A - there's no equivalent to the '.' or '->' operators for
> enums. There's no way to easily say "I'm talking about the A
> defined for enum E1, not the A defined for enum E2".
>
> Can't rely on type inference in assignments; enums are just an
> incredibly weak abstraction in C. There's no range checking
> such that you can only assign one of the defined enumeration
> constants to an object of that enum type.
>
> You'd either need to introduce a C++-style scoping operator like
> E1::A or E2::A, or you'd need to radically revamp and strengthen
> enum semantics. And in the process you'd likely lose some capability
> that people find incredibly useful, such as bitwise-ORing enumeration
> constants together.
>
> enums in C are little more than a way to create symbolic constants for
> integer values. They are not really *enumerated types* like you
> find in other languages.
I think the suggestion is to allow duplicate names only if both the name
and the value happen to match. Thiago's example:
enum E1 { A = 1 };
enum E2 { A = 1 };
would be valid, but changing one of the values:
enum E1 { A = 1 };
enum E2 { A = 2 };
would result in a constraint violation. (I presume the same would apply
if the values are chosen implicitly.)
There's no fundamental reason this couldn't be done, but I don't think
it's useful enough to justify a language change. If you want two enum
types to share values, you can define them as a single type.
(C++ does have an "enum class" feature which, among other things, allows
for duplicate names, but then you always need to refer to "E1::A"
whether it's ambiguous or not.)
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2021-09-28 15:23 -0700 |
| Message-ID | <467a5838-5a51-4b4b-8e01-c28969b69a65n@googlegroups.com> |
| In reply to | #162860 |
On Tuesday, September 28, 2021 at 6:58:00 PM UTC-3, Keith Thompson wrote:
> John Bode <jfbod...@gmail.com> writes:
> > On 9/27/21 12:39 PM, Thiago Adams wrote:
> >> I was wondering if we have some reason to
> >> disallow redeclaration of identical (name/value) enumerators.
> >> enum E1 { A = 1 };
> >> enum E2 { A = 1 };
> >
> > Unlike structs and unions, each enum type is not its own
> > namespace and enumeration constants belong to the "ordinary
> > identifiers" namespace.
> >
> > The question is how you would disambiguate the two definitions
> > of A - there's no equivalent to the '.' or '->' operators for
> > enums. There's no way to easily say "I'm talking about the A
> > defined for enum E1, not the A defined for enum E2".
> >
> > Can't rely on type inference in assignments; enums are just an
> > incredibly weak abstraction in C. There's no range checking
> > such that you can only assign one of the defined enumeration
> > constants to an object of that enum type.
> >
> > You'd either need to introduce a C++-style scoping operator like
> > E1::A or E2::A, or you'd need to radically revamp and strengthen
> > enum semantics. And in the process you'd likely lose some capability
> > that people find incredibly useful, such as bitwise-ORing enumeration
> > constants together.
> >
> > enums in C are little more than a way to create symbolic constants for
> > integer values. They are not really *enumerated types* like you
> > find in other languages.
> I think the suggestion is to allow duplicate names only if both the name
> and the value happen to match. Thiago's example:
> enum E1 { A = 1 };
> enum E2 { A = 1 };
> would be valid, but changing one of the values:
> enum E1 { A = 1 };
> enum E2 { A = 2 };
Yes. (This is allowed in defines for instance)
#define A 1
#define A 1
(
I said: "But we already have a problem today:""
I forgot that in C enumerators are ints. They don't have
the enum type. A is int not enum E1 or enum E2.
So .. this is another reason to allow it?
)
It may be tedious to duplicate enum values or create defines
for the enum value.. so I was thinking.
enum ALL { A, B , C };
enum E { extern A };
The A as it is (same value) is used in E as well.
The value name/value "is imported". The type of A is int.
So what is the objective?
The enum can be used as "set of possible values" and
the same enumerators are reused in different sets.
The advantage of enum over constants is that these sets
can be verified in compiler time in switchs or for valid
assignment or comparisons and make the code clear given a type.
I my code this would be useful because I implement polymorphism
in C using "tags" inside structs. These tags are sets of types I if
I forgot one switch case my code is wrong. I have/use a ALLTAGS enum
because I need unique tags . (enum ensures that)
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-09-29 15:23 +0200 |
| Message-ID | <sj1pd2$4f2$1@dont-email.me> |
| In reply to | #162861 |
On 29/09/2021 00:23, Thiago Adams wrote:
> On Tuesday, September 28, 2021 at 6:58:00 PM UTC-3, Keith Thompson wrote:
>> John Bode <jfbod...@gmail.com> writes:
>>> On 9/27/21 12:39 PM, Thiago Adams wrote:
>>>> I was wondering if we have some reason to
>>>> disallow redeclaration of identical (name/value) enumerators.
>>>> enum E1 { A = 1 };
>>>> enum E2 { A = 1 };
>>>
>>> Unlike structs and unions, each enum type is not its own
>>> namespace and enumeration constants belong to the "ordinary
>>> identifiers" namespace.
>>>
>>> The question is how you would disambiguate the two definitions
>>> of A - there's no equivalent to the '.' or '->' operators for
>>> enums. There's no way to easily say "I'm talking about the A
>>> defined for enum E1, not the A defined for enum E2".
>>>
>>> Can't rely on type inference in assignments; enums are just an
>>> incredibly weak abstraction in C. There's no range checking
>>> such that you can only assign one of the defined enumeration
>>> constants to an object of that enum type.
>>>
>>> You'd either need to introduce a C++-style scoping operator like
>>> E1::A or E2::A, or you'd need to radically revamp and strengthen
>>> enum semantics. And in the process you'd likely lose some capability
>>> that people find incredibly useful, such as bitwise-ORing enumeration
>>> constants together.
>>>
>>> enums in C are little more than a way to create symbolic constants for
>>> integer values. They are not really *enumerated types* like you
>>> find in other languages.
>> I think the suggestion is to allow duplicate names only if both the name
>> and the value happen to match. Thiago's example:
>> enum E1 { A = 1 };
>> enum E2 { A = 1 };
>> would be valid, but changing one of the values:
>> enum E1 { A = 1 };
>> enum E2 { A = 2 };
>
> Yes. (This is allowed in defines for instance)
> #define A 1
> #define A 1
>
> (
> I said: "But we already have a problem today:""
> I forgot that in C enumerators are ints. They don't have
> the enum type. A is int not enum E1 or enum E2.
> So .. this is another reason to allow it?
> )
>
> It may be tedious to duplicate enum values or create defines
> for the enum value.. so I was thinking.
>
> enum ALL { A, B , C };
> enum E { extern A };
>
> The A as it is (same value) is used in E as well.
> The value name/value "is imported". The type of A is int.
>
> So what is the objective?
>
> The enum can be used as "set of possible values" and
> the same enumerators are reused in different sets.
>
> The advantage of enum over constants is that these sets
> can be verified in compiler time in switchs or for valid
> assignment or comparisons and make the code clear given a type.
>
> I my code this would be useful because I implement polymorphism
> in C using "tags" inside structs. These tags are sets of types I if
> I forgot one switch case my code is wrong. I have/use a ALLTAGS enum
> because I need unique tags . (enum ensures that)
>
enums are, in my experience, mostly used for two things. One is when
you want to keep a collection of related flags, states, options, etc.,
in a type :
typedef enum States {
state_startup, state_idle, state_turning_on,
state_on, state_turning_off
} States;
You have a new type, "States" or "enum States" (according to
preference), and values for it. In C++ you'd likely want a scoped enum,
but C does not have them - so just as for namespaces and other nested
naming that C does not have, you use a naming convention for the
enumeration constants. Prefixing with the enumeration name is a common
method. There will not be duplicates or conflicts.
The other major use of enums is simply as named int constants :
enum { no_of_whatsits = 40 };
(In C++, you'd probably just use "const int no_of_whatsits = 40;".)
Here you are only interested in the constants, not the enumeration
types, and there is no particular benefit in keeping them together
inside one enum or splitting them into different enums. There is no
reason for duplications.
So really, I don't see the problem - I can't say I have noticed it in my
own coding.
[toc] | [prev] | [next] | [standalone]
| From | Mark Bluemel <mark.bluemel@gmail.com> |
|---|---|
| Date | 2021-09-30 01:15 -0700 |
| Message-ID | <88ffbaf7-99a4-4b7b-95d9-37625e1895b8n@googlegroups.com> |
| In reply to | #162861 |
On Tuesday, 28 September 2021 at 23:23:40 UTC+1, Thiago Adams wrote: > ... (This is allowed in defines for instance) > #define A 1 > #define A 1 The macro preprocessing (cpp) which handles '#define" has little, if anything, to do with C syntax, and is basically a distraction here.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-09-28 23:31 +0100 |
| Message-ID | <sj053r$6c4$1@dont-email.me> |
| In reply to | #162860 |
On 28/09/2021 22:57, Keith Thompson wrote:
> John Bode <jfbode1029@gmail.com> writes:
>> On 9/27/21 12:39 PM, Thiago Adams wrote:
>>> I was wondering if we have some reason to
>>> disallow redeclaration of identical (name/value) enumerators.
>>> enum E1 { A = 1 };
>>> enum E2 { A = 1 };
>>
>> Unlike structs and unions, each enum type is not its own
>> namespace and enumeration constants belong to the "ordinary
>> identifiers" namespace.
>>
>> The question is how you would disambiguate the two definitions
>> of A - there's no equivalent to the '.' or '->' operators for
>> enums. There's no way to easily say "I'm talking about the A
>> defined for enum E1, not the A defined for enum E2".
>>
>> Can't rely on type inference in assignments; enums are just an
>> incredibly weak abstraction in C. There's no range checking
>> such that you can only assign one of the defined enumeration
>> constants to an object of that enum type.
>>
>> You'd either need to introduce a C++-style scoping operator like
>> E1::A or E2::A, or you'd need to radically revamp and strengthen
>> enum semantics. And in the process you'd likely lose some capability
>> that people find incredibly useful, such as bitwise-ORing enumeration
>> constants together.
>>
>> enums in C are little more than a way to create symbolic constants for
>> integer values. They are not really *enumerated types* like you
>> find in other languages.
>
> I think the suggestion is to allow duplicate names only if both the name
> and the value happen to match. Thiago's example:
>
> enum E1 { A = 1 };
> enum E2 { A = 1 };
>
> would be valid, but changing one of the values:
>
> enum E1 { A = 1 };
> enum E2 { A = 2 };
>
> would result in a constraint violation. (I presume the same would apply
> if the values are chosen implicitly.)
>
> There's no fundamental reason this couldn't be done, but I don't think
> it's useful enough to justify a language change. If you want two enum
> types to share values, you can define them as a single type.
>
> (C++ does have an "enum class" feature which, among other things, allows
> for duplicate names, but then you always need to refer to "E1::A"
> whether it's ambiguous or not.)
That's surprising. With stricter typing, you think it would figure out
that the A here:
enum E2 x = A;
needs to be E2::A.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-09-29 15:36 +0200 |
| Message-ID | <sj1q5a$a7i$1@dont-email.me> |
| In reply to | #162862 |
On 29/09/2021 00:31, Bart wrote:
> On 28/09/2021 22:57, Keith Thompson wrote:
>> John Bode <jfbode1029@gmail.com> writes:
>>> On 9/27/21 12:39 PM, Thiago Adams wrote:
>>>> I was wondering if we have some reason to
>>>> disallow redeclaration of identical (name/value) enumerators.
>>>> enum E1 { A = 1 };
>>>> enum E2 { A = 1 };
>>>
>>> Unlike structs and unions, each enum type is not its own
>>> namespace and enumeration constants belong to the "ordinary
>>> identifiers" namespace.
>>>
>>> The question is how you would disambiguate the two definitions
>>> of A - there's no equivalent to the '.' or '->' operators for
>>> enums. There's no way to easily say "I'm talking about the A
>>> defined for enum E1, not the A defined for enum E2".
>>>
>>> Can't rely on type inference in assignments; enums are just an
>>> incredibly weak abstraction in C. There's no range checking
>>> such that you can only assign one of the defined enumeration
>>> constants to an object of that enum type.
>>>
>>> You'd either need to introduce a C++-style scoping operator like
>>> E1::A or E2::A, or you'd need to radically revamp and strengthen
>>> enum semantics. And in the process you'd likely lose some capability
>>> that people find incredibly useful, such as bitwise-ORing enumeration
>>> constants together.
>>>
>>> enums in C are little more than a way to create symbolic constants for
>>> integer values. They are not really *enumerated types* like you
>>> find in other languages.
>>
>> I think the suggestion is to allow duplicate names only if both the name
>> and the value happen to match. Thiago's example:
>>
>> enum E1 { A = 1 };
>> enum E2 { A = 1 };
>>
>> would be valid, but changing one of the values:
>>
>> enum E1 { A = 1 };
>> enum E2 { A = 2 };
>>
>> would result in a constraint violation. (I presume the same would apply
>> if the values are chosen implicitly.)
>>
>> There's no fundamental reason this couldn't be done, but I don't think
>> it's useful enough to justify a language change. If you want two enum
>> types to share values, you can define them as a single type.
>>
>> (C++ does have an "enum class" feature which, among other things, allows
>> for duplicate names, but then you always need to refer to "E1::A"
>> whether it's ambiguous or not.)
>
> That's surprising. With stricter typing, you think it would figure out
> that the A here:
>
> enum E2 x = A;
>
> needs to be E2::A.
>
It is not remotely surprising - in order to be able to use identifiers
within a nested code structure (I'm using that as a general term, not
just "struct") of some sort, you need to be "inside" the structure, in
the scope of a "using" clause, or you need to give the qualified name.
It would be /convenient/ to have the qualified name handled
automatically here. That would make scoped enums a lot easier in use
and avoid unnecessary wordiness. There is a proposal in the works (I
can't remember off-hand if it got added to the standard) to allow "using
enum E2;" to bring the "E2::" enumerators into scope. That is not ideal
either, but still an improvement in usability.
Maybe new parsing rules for C++ can be figured out that would allow "E2
X = A;", or at least "E2 x { A };". I don't see how it could easily be
done, however, without a lot of complications and side-effects. This
isn't an ad-hoc language where you can just make up the rules as you go
along without a care of how they affect other parts of the language.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-09-29 15:03 +0100 |
| Message-ID | <sj1ro3$ng2$1@dont-email.me> |
| In reply to | #162866 |
On 29/09/2021 14:36, David Brown wrote:
> On 29/09/2021 00:31, Bart wrote:
>> On 28/09/2021 22:57, Keith Thompson wrote:
>>> John Bode <jfbode1029@gmail.com> writes:
>>>> On 9/27/21 12:39 PM, Thiago Adams wrote:
>>>>> I was wondering if we have some reason to
>>>>> disallow redeclaration of identical (name/value) enumerators.
>>>>> enum E1 { A = 1 };
>>>>> enum E2 { A = 1 };
>>>>
>>>> Unlike structs and unions, each enum type is not its own
>>>> namespace and enumeration constants belong to the "ordinary
>>>> identifiers" namespace.
>>>>
>>>> The question is how you would disambiguate the two definitions
>>>> of A - there's no equivalent to the '.' or '->' operators for
>>>> enums. There's no way to easily say "I'm talking about the A
>>>> defined for enum E1, not the A defined for enum E2".
>>>>
>>>> Can't rely on type inference in assignments; enums are just an
>>>> incredibly weak abstraction in C. There's no range checking
>>>> such that you can only assign one of the defined enumeration
>>>> constants to an object of that enum type.
>>>>
>>>> You'd either need to introduce a C++-style scoping operator like
>>>> E1::A or E2::A, or you'd need to radically revamp and strengthen
>>>> enum semantics. And in the process you'd likely lose some capability
>>>> that people find incredibly useful, such as bitwise-ORing enumeration
>>>> constants together.
>>>>
>>>> enums in C are little more than a way to create symbolic constants for
>>>> integer values. They are not really *enumerated types* like you
>>>> find in other languages.
>>>
>>> I think the suggestion is to allow duplicate names only if both the name
>>> and the value happen to match. Thiago's example:
>>>
>>> enum E1 { A = 1 };
>>> enum E2 { A = 1 };
>>>
>>> would be valid, but changing one of the values:
>>>
>>> enum E1 { A = 1 };
>>> enum E2 { A = 2 };
>>>
>>> would result in a constraint violation. (I presume the same would apply
>>> if the values are chosen implicitly.)
>>>
>>> There's no fundamental reason this couldn't be done, but I don't think
>>> it's useful enough to justify a language change. If you want two enum
>>> types to share values, you can define them as a single type.
>>>
>>> (C++ does have an "enum class" feature which, among other things, allows
>>> for duplicate names, but then you always need to refer to "E1::A"
>>> whether it's ambiguous or not.)
>>
>> That's surprising. With stricter typing, you think it would figure out
>> that the A here:
>>
>> enum E2 x = A;
>>
>> needs to be E2::A.
>>
>
> It is not remotely surprising - in order to be able to use identifiers
> within a nested code structure (I'm using that as a general term, not
> just "struct") of some sort, you need to be "inside" the structure, in
> the scope of a "using" clause, or you need to give the qualified name.
Yeah, you're right. It would be tricky anyway, because it can't be
sorted using normal name resolution rules, since it relies on type info
which may not be dealt with until a subsequent stage.
But also, you could have this:
enum E2 {A=1, B, C};
enum E2 A, B;
A = E2::C
B = A;
Is the RHS the variable A (which contains 3), or is it intended to be
E2::A, which is 1?
(This makes me feel better about my own stuff, which can have 'closed'
enums like C, but they need qualifying too:
enum colours = (red, green, blue)
enum lights = (red, amber, green)
colours A = colours.green # can't use A = green)
> Maybe new parsing rules for C++ can be figured out that would allow "E2
> X = A;", or at least "E2 x { A };". I don't see how it could easily be
> done, however, without a lot of complications and side-effects. This
> isn't an ad-hoc language where you can just make up the rules as you go
> along without a care of how they affect other parts of the language.
I don't make up ad-hoc languages; they have to work. You can only cut a
few minor corners.
But I understand parsing C++ can requires some ingenuity anyway, because
the language is so complex and with unexpected and ambiguous
interactions between features.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-09-29 16:46 +0200 |
| Message-ID | <sj1u8e$bds$1@dont-email.me> |
| In reply to | #162867 |
On 29/09/2021 16:03, Bart wrote:
> On 29/09/2021 14:36, David Brown wrote:
>> On 29/09/2021 00:31, Bart wrote:
>>> On 28/09/2021 22:57, Keith Thompson wrote:
>>>> John Bode <jfbode1029@gmail.com> writes:
>>>>> On 9/27/21 12:39 PM, Thiago Adams wrote:
>>>>>> I was wondering if we have some reason to
>>>>>> disallow redeclaration of identical (name/value) enumerators.
>>>>>> enum E1 { A = 1 };
>>>>>> enum E2 { A = 1 };
>>>>>
>>>>> Unlike structs and unions, each enum type is not its own
>>>>> namespace and enumeration constants belong to the "ordinary
>>>>> identifiers" namespace.
>>>>>
>>>>> The question is how you would disambiguate the two definitions
>>>>> of A - there's no equivalent to the '.' or '->' operators for
>>>>> enums. There's no way to easily say "I'm talking about the A
>>>>> defined for enum E1, not the A defined for enum E2".
>>>>>
>>>>> Can't rely on type inference in assignments; enums are just an
>>>>> incredibly weak abstraction in C. There's no range checking
>>>>> such that you can only assign one of the defined enumeration
>>>>> constants to an object of that enum type.
>>>>>
>>>>> You'd either need to introduce a C++-style scoping operator like
>>>>> E1::A or E2::A, or you'd need to radically revamp and strengthen
>>>>> enum semantics. And in the process you'd likely lose some capability
>>>>> that people find incredibly useful, such as bitwise-ORing enumeration
>>>>> constants together.
>>>>>
>>>>> enums in C are little more than a way to create symbolic constants for
>>>>> integer values. They are not really *enumerated types* like you
>>>>> find in other languages.
>>>>
>>>> I think the suggestion is to allow duplicate names only if both the
>>>> name
>>>> and the value happen to match. Thiago's example:
>>>>
>>>> enum E1 { A = 1 };
>>>> enum E2 { A = 1 };
>>>>
>>>> would be valid, but changing one of the values:
>>>>
>>>> enum E1 { A = 1 };
>>>> enum E2 { A = 2 };
>>>>
>>>> would result in a constraint violation. (I presume the same would
>>>> apply
>>>> if the values are chosen implicitly.)
>>>>
>>>> There's no fundamental reason this couldn't be done, but I don't think
>>>> it's useful enough to justify a language change. If you want two enum
>>>> types to share values, you can define them as a single type.
>>>>
>>>> (C++ does have an "enum class" feature which, among other things,
>>>> allows
>>>> for duplicate names, but then you always need to refer to "E1::A"
>>>> whether it's ambiguous or not.)
>>>
>>> That's surprising. With stricter typing, you think it would figure out
>>> that the A here:
>>>
>>> enum E2 x = A;
>>>
>>> needs to be E2::A.
>>>
>>
>> It is not remotely surprising - in order to be able to use identifiers
>> within a nested code structure (I'm using that as a general term, not
>> just "struct") of some sort, you need to be "inside" the structure, in
>> the scope of a "using" clause, or you need to give the qualified name.
>
> Yeah, you're right. It would be tricky anyway, because it can't be
> sorted using normal name resolution rules, since it relies on type info
> which may not be dealt with until a subsequent stage.
>
> But also, you could have this:
>
> enum E2 {A=1, B, C};
> enum E2 A, B;
>
> A = E2::C
> B = A;
>
> Is the RHS the variable A (which contains 3), or is it intended to be
> E2::A, which is 1?
>
> (This makes me feel better about my own stuff, which can have 'closed'
> enums like C, but they need qualifying too:
>
> enum colours = (red, green, blue)
> enum lights = (red, amber, green)
>
> colours A = colours.green # can't use A = green)
>
>> Maybe new parsing rules for C++ can be figured out that would allow "E2
>> X = A;", or at least "E2 x { A };". I don't see how it could easily be
>> done, however, without a lot of complications and side-effects. This
>> isn't an ad-hoc language where you can just make up the rules as you go
>> along without a care of how they affect other parts of the language.
>
>
> I don't make up ad-hoc languages; they have to work. You can only cut a
> few minor corners.
>
> But I understand parsing C++ can requires some ingenuity anyway, because
> the language is so complex and with unexpected and ambiguous
> interactions between features.
>
The aim is to /minimise/ the unexpected or ambiguous interactions (for
those that have learned the language) - that is one of the reasons why
changes are so hard to make in this area, as you have to get experts to
think of all the weirdest corner cases.
I checked on the "using enum" in C++. It was added in C++20, and lets
you write:
enum class colours { red, green, blue };
colours my_favourite_colour;
my_favourite_colour = colours::red;
using enum colours;
my_favourite_colour = blue;
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-09-29 16:08 +0100 |
| Message-ID | <sj1vgt$lfe$1@dont-email.me> |
| In reply to | #162868 |
On 29/09/2021 15:46, David Brown wrote:
> On 29/09/2021 16:03, Bart wrote:
>> Yeah, you're right. It would be tricky anyway, because it can't be
>> sorted using normal name resolution rules, since it relies on type info
>> which may not be dealt with until a subsequent stage.
>>
>> But also, you could have this:
>>
>> enum E2 {A=1, B, C};
>> enum E2 A, B;
>>
>> A = E2::C
>> B = A;
>>
>> Is the RHS the variable A (which contains 3), or is it intended to be
>> E2::A, which is 1?
> I checked on the "using enum" in C++. It was added in C++20, and lets
> you write:
>
> enum class colours { red, green, blue };
> colours my_favourite_colour;
>
> my_favourite_colour = colours::red;
> using enum colours;
> my_favourite_colour = blue;
It took me a while to find something that supported C++20 (godbolt does)
to try it out.
How it works is that if you use:
using enum colours;
then you can't declare:
colours blue;
So the ambiguity I pointed out can't occur.
It stops you using 'int blue;' as well. In fact, all those enum names
become 'open', and you will get the same issues as you have in C with
clashes with other identifiers and other open enums.
(Except that this feature allowes you to restrict those open enums to a
particular scope.)
It doesn't help with my other example either: you can't use both:
using enum colours;
using enum lights;
as 'green' will clash; as well 'red', even though it they have the same
value.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-09-29 20:14 +0200 |
| Message-ID | <sj2adj$emu$1@dont-email.me> |
| In reply to | #162869 |
On 29/09/2021 17:08, Bart wrote:
> On 29/09/2021 15:46, David Brown wrote:
>> On 29/09/2021 16:03, Bart wrote:
>
>>> Yeah, you're right. It would be tricky anyway, because it can't be
>>> sorted using normal name resolution rules, since it relies on type info
>>> which may not be dealt with until a subsequent stage.
>>>
>>> But also, you could have this:
>>>
>>> enum E2 {A=1, B, C};
>>> enum E2 A, B;
>>>
>>> A = E2::C
>>> B = A;
>>>
>>> Is the RHS the variable A (which contains 3), or is it intended to be
>>> E2::A, which is 1?
>
>> I checked on the "using enum" in C++. It was added in C++20, and lets
>> you write:
>>
>> enum class colours { red, green, blue };
>> colours my_favourite_colour;
>>
>> my_favourite_colour = colours::red;
>> using enum colours;
>> my_favourite_colour = blue;
>
> It took me a while to find something that supported C++20 (godbolt does)
> to try it out.
>
> How it works is that if you use:
>
> using enum colours;
>
> then you can't declare:
>
> colours blue;
>
> So the ambiguity I pointed out can't occur.
>
> It stops you using 'int blue;' as well. In fact, all those enum names
> become 'open', and you will get the same issues as you have in C with
> clashes with other identifiers and other open enums.
>
> (Except that this feature allowes you to restrict those open enums to a
> particular scope.)
Of course. Typically, you'll have the "using enum" clause in quite a
small scope - just the block of code where you need it. It's not
something you'd have at file level.
>
> It doesn't help with my other example either: you can't use both:
>
> using enum colours;
> using enum lights;
>
> as 'green' will clash; as well 'red', even though it they have the same
> value.
With strong enumerations, you shouldn't even be thinking of them as
having an integer value - it doesn't make sense to compare the "value"
of a "colours" enumeration element with one from a "lights" enumeration.
That is a large part of the point of having better enumeration types
than were available in C.
[toc] | [prev] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2021-09-29 13:37 -0700 |
| Message-ID | <463ad821-9983-4dae-b997-dba8e756c1fcn@googlegroups.com> |
| In reply to | #162870 |
On Wednesday, September 29, 2021 at 3:14:23 PM UTC-3, David Brown wrote:
> On 29/09/2021 17:08, Bart wrote:
> > On 29/09/2021 15:46, David Brown wrote:
> >> On 29/09/2021 16:03, Bart wrote:
> >
> >>> Yeah, you're right. It would be tricky anyway, because it can't be
> >>> sorted using normal name resolution rules, since it relies on type info
> >>> which may not be dealt with until a subsequent stage.
> >>>
> >>> But also, you could have this:
> >>>
> >>> enum E2 {A=1, B, C};
> >>> enum E2 A, B;
> >>>
> >>> A = E2::C
> >>> B = A;
> >>>
> >>> Is the RHS the variable A (which contains 3), or is it intended to be
> >>> E2::A, which is 1?
> >
> >> I checked on the "using enum" in C++. It was added in C++20, and lets
> >> you write:
> >>
> >> enum class colours { red, green, blue };
> >> colours my_favourite_colour;
> >>
> >> my_favourite_colour = colours::red;
> >> using enum colours;
> >> my_favourite_colour = blue;
> >
> > It took me a while to find something that supported C++20 (godbolt does)
> > to try it out.
> >
> > How it works is that if you use:
> >
> > using enum colours;
> >
> > then you can't declare:
> >
> > colours blue;
> >
> > So the ambiguity I pointed out can't occur.
> >
> > It stops you using 'int blue;' as well. In fact, all those enum names
> > become 'open', and you will get the same issues as you have in C with
> > clashes with other identifiers and other open enums.
> >
> > (Except that this feature allowes you to restrict those open enums to a
> > particular scope.)
> Of course. Typically, you'll have the "using enum" clause in quite a
> small scope - just the block of code where you need it. It's not
> something you'd have at file level.
> >
> > It doesn't help with my other example either: you can't use both:
> >
> > using enum colours;
> > using enum lights;
> >
> > as 'green' will clash; as well 'red', even though it they have the same
> > value.
> With strong enumerations, you shouldn't even be thinking of them as
> having an integer value - it doesn't make sense to compare the "value"
> of a "colours" enumeration element with one from a "lights" enumeration.
> That is a large part of the point of having better enumeration types
> than were available in C.
I don't mind too much about enumerators being integers into C standard.
But I would like compiler diagnostics (and I guess they already exist)
when enun types are mixed.
Attributes added a new punctuator in C23 that is '::' to be able to parse
scoped attributes like [[aa::bb]]
Maybe someday this punctuator will be used for something else in C,
to create scoped variables..
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2021-09-29 18:25 -0700 |
| Message-ID | <87tui2j1m3.fsf@nosuchdomain.example.com> |
| In reply to | #162870 |
David Brown <david.brown@hesbynett.no> writes:
[...]
> With strong enumerations, you shouldn't even be thinking of them as
> having an integer value - it doesn't make sense to compare the "value"
> of a "colours" enumeration element with one from a "lights" enumeration.
> That is a large part of the point of having better enumeration types
> than were available in C.
C++ scoped enumeration types do have well-defined integer
representations. You can even specify them in the declaration:
enum class foo { zero = 0, one = 1 };
There's no implicit conversion from foo to int, but you can use a cast;
for example (int)foo::zero == 0.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-09-30 12:45 +0200 |
| Message-ID | <sj44gi$odk$1@dont-email.me> |
| In reply to | #162873 |
On 30/09/2021 03:25, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
> [...]
>> With strong enumerations, you shouldn't even be thinking of them as
>> having an integer value - it doesn't make sense to compare the "value"
>> of a "colours" enumeration element with one from a "lights" enumeration.
>> That is a large part of the point of having better enumeration types
>> than were available in C.
>
> C++ scoped enumeration types do have well-defined integer
> representations. You can even specify them in the declaration:
>
> enum class foo { zero = 0, one = 1 };
>
> There's no implicit conversion from foo to int, but you can use a cast;
> for example (int)foo::zero == 0.
>
Sure - and for some use-cases that might be useful.
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.
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2021-09-30 07:36 -0700 |
| Message-ID | <bf3ac5ed-f44b-4f8d-9ffe-ad9583ade948n@googlegroups.com> |
| In reply to | #162875 |
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.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2021-10-01 09:20 +0200 |
| Message-ID | <sj6csf$dvm$1@dont-email.me> |
| In reply to | #162881 |
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 does not use or rely on underlying integer values in any way -
there is no need even to have the same order in the array definition as
in the enumeration.
For convenience (and for standard C++) you might define such an array
without designated initialisers, but you are still trying to view the
enumeration elements as abstract symbols, not as merely names for
integer constants.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 11:24 +0100 |
| Message-ID | <sj6nkg$4am$1@dont-email.me> |
| In reply to | #162887 |
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:
* Each enum occurs three times (maybe it's to mimic loop variables!)
* There is no protection against defining [red] as "green"
* Entries can be in any order, so no protection against missing some out
* No dimension is given, so no protection against adding [amber] =
"amber" (unless amber's value clashes with red, green or blue
* If red, green and blue are given their own arbitrary values (so
non-consecutive), then this can generate, I assume, some arbitrary-sized
sparse array
* I can define [blue] twice with different values
* The whole thing consists of 3 components, with two visible global (eg.
in a header) and one needing to be kept apart.
I haven't really this either in my own language; I can never be bother
to do it properly. However I do use this feature:
tabledata() []ichar colour_names =
(red, $),
(green, $),
(blue, $),
end
The restriction is that values need to be consecutive, but this is
virtually always the case. (There are other features for named constants.)
* Each enum name occurs exactly once ($ can be replaced with a regular
string
* 'red' will always be "red" (unless overridden)
* It's impossible to miss out 'green' without removing it completely
* The dimension is always the number of enums; it's more obvious is
rogue values are added
* The ordering occurs in one place (swap red and blue, and it still
works, no other changes needed)
* You can't repeat the same enum more than once
* The whole thing is defined in one place. To share, mark it 'global'.
* Values must be consecutive (there are other features for regular named
constants)
* The restriction is that the start value, normally 1, can be overridden
using eg. red=0, but the array lwb ([0:] must match too, not checked.
* The big advantage it being able to add further arrays (extra columns)
with other related data with the same advantage of automatic correspondence.
> This does not use or rely on underlying integer values in any way -
> there is no need even to have the same order in the array definition as
> in the enumeration.
I fail to see that as an advantage. A compact, consecutive sequence
makes enums more suitable for:
* Switch-case values (allows a jump table to be used)
* Array indexing
* -- and ++ operations
* Allowing ordered comparisons, where ordering is important
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2021-10-01 04:49 -0700 |
| Message-ID | <e468277c-6174-4591-ac91-4ba7dcbf893cn@googlegroups.com> |
| In reply to | #162891 |
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.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2021-10-01 13:06 +0100 |
| Message-ID | <sj6tkk$m4p$1@dont-email.me> |
| In reply to | #162892 |
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.
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | comp.lang.c
csiph-web