digitalmars.D - Wrong enum comparisons
- bearophile (17/17) May 27 2012 In some code I have created a small bug that can be reduced to
- Mehrdad (2/2) May 27 2012 The *real* question is, why don't you need the "E2" qualifier
- Mehrdad (3/5) May 27 2012 well never mind, I need sleep... I didn't see you were using
- Jonathan M Davis (7/25) May 27 2012 If assert(E1.A == E2.D) wouldn't compile, then this is clearly a bug wit...
- Denis Shelomovskij (17/33) May 28 2012 Enumerations are in very poor state in D now. May be, it should be
- Dmitry Olshansky (4/39) May 28 2012 --
- bearophile (16/20) May 28 2012 I think D enums need to become a bit more strict (so you can't
- Araq (3/3) May 28 2012 Pascal got type safe enums and sets of enums (aka "flags") right
- Marco Leise (42/45) May 28 2012 Yes, I really like Pascal for that feature. Actually it is a mix of feat...
- foobar (15/54) May 28 2012 I have to loudly object to this definition. Given a typical
- Andrei Alexandrescu (22/31) May 28 2012 Depends on what the concept is. The archetype for "enumerating" is
- bearophile (25/36) May 28 2012 I filed this first problem in 2010-03 (I have not filed the
- foobar (12/48) May 28 2012 It depends on what exactly the general concept is, is this a
- Andrei Alexandrescu (14/25) May 28 2012 Well ordinal could always be a function that does the cast...
- Jonathan M Davis (8/38) May 28 2012 enum does need some work, but I think that the fact that it can be both ...
- Andrei Alexandrescu (3/9) May 28 2012 I agree it is possible to fix enum.
- bearophile (9/12) May 28 2012 Thank you for your answers Andrei. I have filed an enhancement
- LemonBoy (6/18) Jan 14 2017 Alright, ~5 years have passed and no response has been heard so I
- Era Scarecrow (6/14) Jan 14 2017 I could never wrap my head around how the Java Enum/Class was
In some code I have created a small bug that can be reduced to something like this, that the D compiler has not caught at compile-time: enum E1 { A, B } enum E2 { C, D } void main() { E1[2] a; with (E2) assert(a[0] == D); } Why isn't D able to statically tell when you compare values of different enums? How much work is implementing this compile-time test inside the D front-end? Thank you, bye, bearophile
May 27 2012
The *real* question is, why don't you need the "E2" qualifier when you say "D"?
May 27 2012
On Monday, 28 May 2012 at 05:33:28 UTC, Mehrdad wrote:The *real* question is, why don't you need the "E2" qualifier when you say "D"?well never mind, I need sleep... I didn't see you were using 'with'.
May 27 2012
On Sunday, May 27, 2012 21:45:22 bearophile wrote:In some code I have created a small bug that can be reduced to something like this, that the D compiler has not caught at compile-time: enum E1 { A, B } enum E2 { C, D } void main() { E1[2] a; with (E2) assert(a[0] == D); } Why isn't D able to statically tell when you compare values of different enums? How much work is implementing this compile-time test inside the D front-end?If assert(E1.A == E2.D) wouldn't compile, then this is clearly a bug with with. If assert(E1.A == E2.d) compiles, then this behavior is clearly intended. My guess would be that this is a bug with with, but I don't think that I've ever tried to compare two different types of enums like that before, so I'd have to check. - Jonathan M Davis
May 27 2012
27.05.2012 23:45, bearophile написал:In some code I have created a small bug that can be reduced to something like this, that the D compiler has not caught at compile-time: enum E1 { A, B } enum E2 { C, D } void main() { E1[2] a; with (E2) assert(a[0] == D); } Why isn't D able to statically tell when you compare values of different enums? How much work is implementing this compile-time test inside the D front-end? Thank you, bye, bearophileEnumerations are in very poor state in D now. May be, it should be deprecated just like typedef and be library-implemented. Why? Because we do need really strict type/operation checking with enum so one have to write explicitly casts to do non-standard things. The two main enumeration types are: * list - must hold only one value, only opAssign and opEqual are allowed, by default nextValue = prevValue + 1 starting with 0 * flags - must hold superposition of values, like list, but binary operations are also allowed, by default nextValue = prevValue << 1 starting with 1 These also allow finally implement right to!string for flags. By the way, current enums can be modified to correspond "list" enumeration and flags can be added as library component. -- Денис В. Шеломовский Denis V. Shelomovskij
May 28 2012
On 28.05.2012 12:58, Denis Shelomovskij wrote:27.05.2012 23:45, bearophile написал:+1. Well said, hard to add anything ;)In some code I have created a small bug that can be reduced to something like this, that the D compiler has not caught at compile-time: enum E1 { A, B } enum E2 { C, D } void main() { E1[2] a; with (E2) assert(a[0] == D); } Why isn't D able to statically tell when you compare values of different enums? How much work is implementing this compile-time test inside the D front-end? Thank you, bye, bearophileEnumerations are in very poor state in D now. May be, it should be deprecated just like typedef and be library-implemented. Why? Because we do need really strict type/operation checking with enum so one have to write explicitly casts to do non-standard things. The two main enumeration types are: * list - must hold only one value, only opAssign and opEqual are allowed, by default nextValue = prevValue + 1 starting with 0 * flags - must hold superposition of values, like list, but binary operations are also allowed, by default nextValue = prevValue << 1 starting with 1These also allow finally implement right to!string for flags. By the way, current enums can be modified to correspond "list" enumeration and flags can be added as library component.-- Dmitry Olshansky
May 28 2012
Denis Shelomovskij:Enumerations are in very poor state in D now. ... By the way, current enums can be modified to correspond "list" enumeration and flags can be added as library component.I think D enums need to become a bit more strict (so you can't equal elements of different enums). Later I think the messy situation with enum attributes needs to be cleared up and improved, removing most of the name clases between the current attributes and enum item names (http://d.puremagic.com/issues/show_bug.cgi?id=4997 ). And later *simple* flags are implementable in Phobos. First step is to make them less sloppy and more strict, otherwise successive work will be founded on quicksand (but as long as such threads generate no concrete answers from D designers, we are just wasting time here). In GitHub there are many patches open, applying several of them will reduce many current pain points of using D. Bye, bearophile
May 28 2012
Pascal got type safe enums and sets of enums (aka "flags") right in the 60ies. Too bad not even Ada copied this nice feature. Fortunately, Nimrod does.
May 28 2012
Am Mon, 28 May 2012 13:48:23 +0200 schrieb "Araq" <rumpf_a web.de>:Pascal got type safe enums and sets of enums (aka "flags") right in the 60ies. Too bad not even Ada copied this nice feature. Fortunately, Nimrod does.Yes, I really like Pascal for that feature. Actually it is a mix of features I miss from Pascal in D: 1. Ranged ordinal types type Month = 1 .. 12; type AsciiLower = 'a' .. 'z'; type Hours = 0 .. 24; As far as I remember it, the compiler chooses the optimal ordinal type derived from the start and end constant. It is a form of self-documenting code and it could work nice with "checked integers", if they are ever implemented in D. 2. Enumerations type Day = ( Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday ); Ord(x) gives the ordinal value of an enumeration variable, e.g. neither implicit conversion to integer types nor casts, but a language defined, clean way to convert from enums to their inherent integer representation. 3. Sets I'd like to start with the enumeration for the days of a week, because I think both Pascal and D look intuitive here: Pascal: type Day = ( Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday ); var weekday : Day; weekday = Monday; weekday = Succ(weekday); // Tuesday D: enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday } Day weekday = Monday; weekday++; // Tuesday But D lacks proper sets, which turn any enumeration into a set: type DaySet = set of Day; Note how Pascal naturally maps the enum values (0 through 6) to 1, 2, 4, 8, 16, 32 and 64 internally, while in C or D you need to do this manually or by importing a module that offers a template solution. Further you can apply the typical operators to sets: var workdays : DaySet; workdays = [ Monday .. Friday ]; // pretty nice shortcut to set a range of flags if Monday in workdays then ... // check if set contains a value weekdays = weekdays + [ Monday, Sunday ] // union (adds Sunday) weekdays = weekdays - [ Monday, Sunday ] // complement (removes Monday) weekdays = weekdays * [ Monday, Sunday ] // intersection (leaves Monday) // (in)euqality, subset and superset are also implemented I think flag sets are needed often enough (file open modes, drawing hints, enabled features) to warrant that feature and they enable some programming styles that are awkward with what C gives you at hand. 123. All these integrate nicely with each other Create an array that holds a value of 0 to 24 for each week day: var hoursPerDay : array[Day] of Hours; hoursPerDay[Monday] = 8; In general I had a good experience with Pascal when it comes to defining and checking flags. -- Marco
May 28 2012
On Monday, 28 May 2012 at 08:58:29 UTC, Denis Shelomovskij wrote:27.05.2012 23:45, bearophile написал:I have to loudly object to this definition. Given a typical enumeration such as: enum color {Blue, Green, Red}; Who's to say that Blue must equal 0? This is conceptually plain *wrong*. A conceptually correct enumeration must NOT expose such implementation details as the very poor C/D style enums do. See functional languages such as ML for a correct implementation and also Java 5 Enums (similar but with an OO flavor). The second point is conceptually *wrong* as well - a set of flag values is exactly that - _a set_. The type-safe correct way is to use a set!MyEnum to properly represent this (of course with a specialized implementation for this using bits for performance reasons).In some code I have created a small bug that can be reduced to something like this, that the D compiler has not caught at compile-time: enum E1 { A, B } enum E2 { C, D } void main() { E1[2] a; with (E2) assert(a[0] == D); } Why isn't D able to statically tell when you compare values of different enums? How much work is implementing this compile-time test inside the D front-end? Thank you, bye, bearophileEnumerations are in very poor state in D now. May be, it should be deprecated just like typedef and be library-implemented. Why? Because we do need really strict type/operation checking with enum so one have to write explicitly casts to do non-standard things. The two main enumeration types are: * list - must hold only one value, only opAssign and opEqual are allowed, by default nextValue = prevValue + 1 starting with 0 * flags - must hold superposition of values, like list, but binary operations are also allowed, by default nextValue = prevValue << 1 starting with 1 These also allow finally implement right to!string for flags. By the way, current enums can be modified to correspond "list" enumeration and flags can be added as library component.
May 28 2012
On 5/28/12 8:19 AM, foobar wrote:I have to loudly object to this definition. Given a typical enumeration such as: enum color {Blue, Green, Red}; Who's to say that Blue must equal 0? This is conceptually plain *wrong*. A conceptually correct enumeration must NOT expose such implementation details as the very poor C/D style enums do.Depends on what the concept is. The archetype for "enumerating" is natural numbers, and in that view there's nothing wrong to attach a natural ordinal to each element of an enumeration. I do agree that it's wrong to _conflate_ the enumerated value with it ordinal, so in this program neither comparison should compile without an explicit cast: enum E1 { A, B } enum E2 { C, D } void main() { E1 a; assert(a == 0); assert(a == E2.C); } The first one is probably difficult to disallow at this time, but the second one almost always indicates a bug, confusion, or abuse on the user side. We should disallow it.See functional languages such as ML for a correct implementation and also Java 5 Enums (similar but with an OO flavor).I've always found it amusing to watch what a kitchen sink Java enumerations have become. It's as if someone said, "so you complain Java doesn't have enum? I'll give you enum!" I think we shouldn't copy that design. Andrei
May 28 2012
Andrei Alexandrescu:I do agree that it's wrong to _conflate_ the enumerated value with it ordinal, so in this program neither comparison should compile without an explicit cast: enum E1 { A, B } enum E2 { C, D } void main() { E1 a; assert(a == 0); assert(a == E2.C); } The first one is probably difficult to disallow at this time,I filed this first problem in 2010-03 (I have not filed the Enum1==Enum2 problem yet): http://d.puremagic.com/issues/show_bug.cgi?id=3999 This is a small breaking change, but it doesn't introduce bugs in already written code, it turns into compile-time errors code that currently compiles. I think the usual way to solve this compile-time error is to use a cast (or sometimes use this safe to!() enhancement: http://d.puremagic.com/issues/show_bug.cgi?id=8143 ). C++11 has "solved" this compatibility problem creating another kind of enum, referred as "enum class": enum class Foo { V1 = 10 }; int main() { int b = Foo::V1 == 10; } test.cpp: In function 'int main()': test.cpp:3: error: no match for 'operator==' in '(Foo)10 == 10' test.cpp:3: note: candidates are: operator==(int, int) <built-in> The disadvantage of doing this is the complexity increase of the language. I don't know how do you estimate how much difficult is to perform small breaking changes in the language. Bye, bearophile
May 28 2012
On Monday, 28 May 2012 at 13:47:47 UTC, Andrei Alexandrescu wrote:On 5/28/12 8:19 AM, foobar wrote:It depends on what exactly the general concept is, is this a predefined set of values or is it an ordered list. I'd argue that the set is more general and we shouldn't force an ordering when one isn't strictly required. Of course, the programmer should be able to add an ordering when it's required. How to implement an order: IMO casts usually indicate code smell. I think something like Color.Red.ordinal states the intention much better than a cast. Could you please explain the issues you see in Java's Enum that cause you to reject such a design?I have to loudly object to this definition. Given a typical enumeration such as: enum color {Blue, Green, Red}; Who's to say that Blue must equal 0? This is conceptually plain *wrong*. A conceptually correct enumeration must NOT expose such implementation details as the very poor C/D style enums do.Depends on what the concept is. The archetype for "enumerating" is natural numbers, and in that view there's nothing wrong to attach a natural ordinal to each element of an enumeration. I do agree that it's wrong to _conflate_ the enumerated value with it ordinal, so in this program neither comparison should compile without an explicit cast: enum E1 { A, B } enum E2 { C, D } void main() { E1 a; assert(a == 0); assert(a == E2.C); } The first one is probably difficult to disallow at this time, but the second one almost always indicates a bug, confusion, or abuse on the user side. We should disallow it.See functional languages such as ML for a correct implementation and also Java 5 Enums (similar but with an OO flavor).I've always found it amusing to watch what a kitchen sink Java enumerations have become. It's as if someone said, "so you complain Java doesn't have enum? I'll give you enum!" I think we shouldn't copy that design. Andrei
May 28 2012
On 5/28/12 1:07 PM, foobar wrote:It depends on what exactly the general concept is, is this a predefined set of values or is it an ordered list. I'd argue that the set is more general and we shouldn't force an ordering when one isn't strictly required. Of course, the programmer should be able to add an ordering when it's required.Ascribing ordinal values is not ordering.How to implement an order: IMO casts usually indicate code smell. I think something like Color.Red.ordinal states the intention much better than a cast.Well ordinal could always be a function that does the cast...Could you please explain the issues you see in Java's Enum that cause you to reject such a design?Too big for what it does. Not worth getting into details as I don't have a strong opinion or one of much consequence. At the end of the day, it is fairly clear to me that D's enum is in no interesting point on the convenience/safety tradeoff scale, and doesn't offer anything worth its presence in the language. It's just a bit less broken than typedef, which was just egregious. No surprise there - aspects of the language that received attention (e.g. floating point) turned out well whereas those that didn't (either through incomplete analysis or inheriting a bad design) turned out rather badly. I'd put typedef (good thing it's gone), lazy, and enum in the latter category. Andrei
May 28 2012
On Monday, May 28, 2012 14:21:14 Andrei Alexandrescu wrote:On 5/28/12 1:07 PM, foobar wrote:enum does need some work, but I think that the fact that it can be both built- in types such as int as well as user-defined structs is great. It essentially gives us the best of both worlds (basic enums such as in C/C++ and more complex types as in Java). It's some of the minor details where things tend to not work as well as would be nice (e.g. some of the arithmetic that's considered legal on enums which are integral values). - Jonathan M DavisIt depends on what exactly the general concept is, is this a predefined set of values or is it an ordered list. I'd argue that the set is more general and we shouldn't force an ordering when one isn't strictly required. Of course, the programmer should be able to add an ordering when it's required.Ascribing ordinal values is not ordering.How to implement an order: IMO casts usually indicate code smell. I think something like Color.Red.ordinal states the intention much better than a cast.Well ordinal could always be a function that does the cast...Could you please explain the issues you see in Java's Enum that cause you to reject such a design?Too big for what it does. Not worth getting into details as I don't have a strong opinion or one of much consequence. At the end of the day, it is fairly clear to me that D's enum is in no interesting point on the convenience/safety tradeoff scale, and doesn't offer anything worth its presence in the language. It's just a bit less broken than typedef, which was just egregious. No surprise there - aspects of the language that received attention (e.g. floating point) turned out well whereas those that didn't (either through incomplete analysis or inheriting a bad design) turned out rather badly. I'd put typedef (good thing it's gone), lazy, and enum in the latter category.
May 28 2012
On 5/28/12 2:37 PM, Jonathan M Davis wrote:enum does need some work, but I think that the fact that it can be both built- in types such as int as well as user-defined structs is great. It essentially gives us the best of both worlds (basic enums such as in C/C++ and more complex types as in Java). It's some of the minor details where things tend to not work as well as would be nice (e.g. some of the arithmetic that's considered legal on enums which are integral values).I agree it is possible to fix enum. Andrei
May 28 2012
Andrei Alexandrescu:I do agree that it's wrong to _conflate_ the enumerated value with it ordinal,I agree it is possible to fix enum.Thank you for your answers Andrei. I have filed an enhancement request: http://d.puremagic.com/issues/show_bug.cgi?id=8157 Issue 8157 is a subset of issue 3999, so they don't interfere with each other in Bugzilla. I'd like to receive a comment from Walter :-) Bye, bearophile
May 28 2012
On Monday, 28 May 2012 at 21:01:43 UTC, bearophile wrote:Andrei Alexandrescu:Alright, ~5 years have passed and no response has been heard so I think it's right about time to get the ball rolling (again). that's IMO a solid first step in the right direction. Feel free to continue the discussion here or on the GH issue.I do agree that it's wrong to _conflate_ the enumerated value with it ordinal,I agree it is possible to fix enum.Thank you for your answers Andrei. I have filed an enhancement request: http://d.puremagic.com/issues/show_bug.cgi?id=8157 Issue 8157 is a subset of issue 3999, so they don't interfere with each other in Bugzilla. I'd like to receive a comment from Walter :-) Bye, bearophile
Jan 14 2017
On Monday, 28 May 2012 at 13:47:47 UTC, Andrei Alexandrescu wrote:On 5/28/12 8:19 AM, foobar wrote:I could never wrap my head around how the Java Enum/Class was suppose to work or why. Also couldn't figure why they wouldn't have a simple structure i could pass around that held data by itself without creating a class from it.See functional languages such as ML for a correct implementation and also Java 5 Enums (similar but with an OO flavor).I've always found it amusing to watch what a kitchen sink Java enumerations have become. It's as if someone said, "so you complain Java doesn't have enum? I'll give you enum!" I think we shouldn't copy that design.
Jan 14 2017