digitalmars.D.learn - enum inheritance
- JS (21/21) Jul 14 2013 It would be nice to be able to use enums in a hierarchical way:
- JS (6/6) Jul 14 2013 BTW, the usefulness is to group sub-enums into the same range.
- JS (4/10) Jul 14 2013 I guess a more intelligent structure is needed so changes in the
- Mike Parker (2/8) Jul 15 2013 if( v >= Red && v <= LastRed )
- JS (38/49) Jul 15 2013 The problem is if a binary is already compiled and changes are
- Dicebot (5/6) Jul 15 2013 I think closest solution you can get is having bunch of private
- JS (22/28) Jul 15 2013 That might solve the partitioning problem and solve part of the
- Dicebot (8/9) Jul 15 2013 I see. No, unfortunately, I am currently not aware of a way to
- bearophile (26/47) Aug 02 2013 In Ada you can define ranged types, and there is a keyword to
It would be nice to be able to use enums in a hierarchical way: enum colors { enum Red { RedOrange, ... } enum Green { GreenBlue, ...} enum Blue { BlueYellow, ... } ... } which would be the same as the flattened version, enum colors { Red, RedOrange, ..., Green, GreenBlue, ..., Blue, BlueYellow, ..., ... } but we could dereference such as colors.Red.RedOrange, colors.Blue, colors.Green.GreenBlue, (This isn't a great example but demonstrates what I would like to be able to do) Is anything like this possible?
Jul 14 2013
BTW, the usefulness is to group sub-enums into the same range. This would make it easy/efficient to branch over a range in the enum: if (v in colors.Red) { v is a color in red } instead of if (v is color.Red || v is color.RedOrange || ...)
Jul 14 2013
On Monday, 15 July 2013 at 04:27:42 UTC, JS wrote:BTW, the usefulness is to group sub-enums into the same range. This would make it easy/efficient to branch over a range in the enum: if (v in colors.Red) { v is a color in red } instead of if (v is color.Red || v is color.RedOrange || ...)I guess a more intelligent structure is needed so changes in the enum do not break binaries. (although this is already somewhat of an issue with enums as changes in order requires a re-compilation)
Jul 14 2013
On Monday, 15 July 2013 at 04:27:42 UTC, JS wrote:BTW, the usefulness is to group sub-enums into the same range. This would make it easy/efficient to branch over a range in the enum: if (v in colors.Red) { v is a color in red } instead of if (v is color.Red || v is color.RedOrange || ...)if( v >= Red && v <= LastRed )
Jul 15 2013
On Monday, 15 July 2013 at 07:37:36 UTC, Mike Parker wrote:On Monday, 15 July 2013 at 04:27:42 UTC, JS wrote:The problem is if a binary is already compiled and changes are made. If a red color is inserted your range has changed. Also, it requires you to keep your entries sorted properly. Also, a "LastRed" entry is needed and there is no other reason to have it. Since an int is 4B entries, and that's way more than most will use, It think it's better to be able to have the compiler partition of the range for you and save "space" for future entries. This prevents an addition entry from screwing up everything. e.g., enum colors { enum Red : 1M { RedOrange, ... } enum Green : 2M { ... } ... } In this case, one can have up to 1M unordered sub entries(should be plenty) and ~4.2k main entries. One could order further, enum colors { enum Red : 1M { enum RedOrange : 10k { }, ... } enum Green : 2M { ... } ... } Basically the idea is to distribute the elements of enum and sub enums in such a way as to maximize space between each entry. This allows any binaries using an old version not to crash and burn. This does require an estimation of the maximum entries that will be used. I'm particularly thinking of a messaging system where ints can be passed around with 10's of thousands of defined messages with messages grouped into common functionality(hence the inheritance aspect) and adding new messages won't ruin the communications between new and old systems. Nested switch statements can easily and quickly pare down determination of a message(not as fast as a flattened hierarchy though).BTW, the usefulness is to group sub-enums into the same range. This would make it easy/efficient to branch over a range in the enum: if (v in colors.Red) { v is a color in red } instead of if (v is color.Red || v is color.RedOrange || ...)if( v >= Red && v <= LastRed )
Jul 15 2013
Maybe this way? ---- final abstract class Colors { enum Red { RedOrange } enum Green { GreenBlue} enum Blue { BlueYellow } } void main() { Colors.Red foo = Colors.Red.RedOrange; assert(foo >= Colors.Red.min && foo <= Colors.Red.max); } ----
Jul 15 2013
On Monday, 15 July 2013 at 08:20:20 UTC, Namespace wrote:Maybe this way? ---- final abstract class Colors { enum Red { RedOrange } enum Green { GreenBlue} enum Blue { BlueYellow } } void main() { Colors.Red foo = Colors.Red.RedOrange; assert(foo >= Colors.Red.min && foo <= Colors.Red.max); } ----but RedOrange and GreenBlue have the same value!
Jul 15 2013
On Monday, 15 July 2013 at 10:17:08 UTC, JS wrote:On Monday, 15 July 2013 at 08:20:20 UTC, Namespace wrote:Also, Colors.Red is not a value!Maybe this way? ---- final abstract class Colors { enum Red { RedOrange } enum Green { GreenBlue} enum Blue { BlueYellow } } void main() { Colors.Red foo = Colors.Red.RedOrange; assert(foo >= Colors.Red.min && foo <= Colors.Red.max); } ----but RedOrange and GreenBlue have the same value!
Jul 15 2013
On Monday, 15 July 2013 at 10:23:22 UTC, JS wrote:On Monday, 15 July 2013 at 10:17:08 UTC, JS wrote:Then: good luck.On Monday, 15 July 2013 at 08:20:20 UTC, Namespace wrote:Also, Colors.Red is not a value!Maybe this way? ---- final abstract class Colors { enum Red { RedOrange } enum Green { GreenBlue} enum Blue { BlueYellow } } void main() { Colors.Red foo = Colors.Red.RedOrange; assert(foo >= Colors.Red.min && foo <= Colors.Red.max); } ----but RedOrange and GreenBlue have the same value!
Jul 15 2013
On Monday, 15 July 2013 at 04:24:59 UTC, JS wrote:...I think closest solution you can get is having bunch of private enum definitions and combining them into single public one via compile-time reflection. Something like "mixin(generateEnum!(Red, Green, blue))".
Jul 15 2013
On Monday, 15 July 2013 at 11:00:59 UTC, Dicebot wrote:On Monday, 15 July 2013 at 04:24:59 UTC, JS wrote:That might solve the partitioning problem and solve part of the hierarchical problem but won't allow submember access, e.g., colors.red.redorange. It seems like a good start though. I imagine one could potentially build up a set of nested struct with immutable members representing the enums: final immutable struct Colors { final immutable struct Red { private immutable int _Red = 10000; immutable int RedOrange = 10001; alias _Red this; // obviously doesn't work } final immutable struct Green { immutable int Green = 20000; } } but with the glitch on the alias(Colors.Red doesn't work)... which sort of throws a kink in the solution making more than a 2-deep nest useless....I think closest solution you can get is having bunch of private enum definitions and combining them into single public one via compile-time reflection. Something like "mixin(generateEnum!(Red, Green, blue))".
Jul 15 2013
On Monday, 15 July 2013 at 13:01:05 UTC, JS wrote:...I see. No, unfortunately, I am currently not aware of a way to make symbol act as type and and value at the same time. However it is worth noting that you use plenty of excessive attributes. Currently it is not a compiler error but makes code much harder to read and confusing. For example, "final" has no meaning for structs as they can't be inherited from anyway. Duplicating immutable is also excessive because it is transitive.
Jul 15 2013
On Monday, 15 July 2013 at 13:47:10 UTC, Dicebot wrote:On Monday, 15 July 2013 at 13:01:05 UTC, JS wrote:Original I had it as a class. I'm not sure if it matters much between a class and a struct though? In any case, I solved this problem by using an attribute to test instead of using isMutable. Obviously this requires adding a symbol but not a huge deal. e.g., Enum immutable struct ... and hasAttribute(T, Enum) replaces isMutable(T)....I see. No, unfortunately, I am currently not aware of a way to make symbol act as type and and value at the same time. However it is worth noting that you use plenty of excessive attributes. Currently it is not a compiler error but makes code much harder to read and confusing. For example, "final" has no meaning for structs as they can't be inherited from anyway. Duplicating immutable is also excessive because it is transitive.
Jul 15 2013
On Monday, 15 July 2013 at 18:26:26 UTC, JS wrote:Original I had it as a class. I'm not sure if it matters much between a class and a struct though?It does matter a lot. structs are value types, classes are polymorphic reference types. There is a nice summary table in docs: http://dlang.org/struct.html , please notice that "inheritance" and this "final" applies only for classes.In any case, I solved this problem by using an attribute to test instead of using isMutable. Obviously this requires adding a symbol but not a huge deal. e.g., Enum immutable struct ... and hasAttribute(T, Enum) replaces isMutable(T).Yeah, that may work, despite being not that pretty. I personally think it is better for now chose some not-that-elegant approach in your code, at least until enums will become more robust. Currently it tries to workaround some very basic type system assumptions, which rarely ends good.
Jul 15 2013
On Monday, 15 July 2013 at 19:24:27 UTC, Dicebot wrote:On Monday, 15 July 2013 at 18:26:26 UTC, JS wrote:um, but I'm only using the type at compile time. the immutable fields in it all result in compile time literals... the struct itself never gets used at run time... so there is no runtime difference(or shouldn't be) except maybe a little more wasted space with the class unless it is optimized out.Original I had it as a class. I'm not sure if it matters much between a class and a struct though?It does matter a lot. structs are value types, classes are polymorphic reference types. There is a nice summary table in docs: http://dlang.org/struct.html , please notice that "inheritance" and this "final" applies only for classes.I really don't have 10 years to wait for enums to become more robust and hope in the way I am trying to use them.In any case, I solved this problem by using an attribute to test instead of using isMutable. Obviously this requires adding a symbol but not a huge deal. e.g., Enum immutable struct ... and hasAttribute(T, Enum) replaces isMutable(T).Yeah, that may work, despite being not that pretty. I personally think it is better for now chose some not-that-elegant approach in your code, at least until enums will become more robust. Currently it tries to workaround some very basic type system assumptions, which rarely ends good.
Jul 15 2013
JS:It would be nice to be able to use enums in a hierarchical way: enum colors { enum Red { RedOrange, ... } enum Green { GreenBlue, ...} enum Blue { BlueYellow, ... } ... } which would be the same as the flattened version, enum colors { Red, RedOrange, ..., Green, GreenBlue, ..., Blue, BlueYellow, ..., ... } but we could dereference such as colors.Red.RedOrange, colors.Blue, colors.Green.GreenBlue, (This isn't a great example but demonstrates what I would like to be able to do) Is anything like this possible?In Ada you can define ranged types, and there is a keyword to define their subtypes: type Day is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday); -- Derived types, they are new incompatible with the original: type Business_Day is new Day range Monday .. Friday; type Weekend_Day is new Day range Saturday .. Sunday; -- Subtypes that convert implicitly to their supertype: subtype Business_Day is Day range Monday .. Friday; subtype Weekend_Day is Day range Saturday .. Sunday; subtype Dice_Throw is Integer range 1 .. 6; The Ada compiler enforces static typing where possible, and uses dynamic tests where it can't (and the dynamic tests can be disabled with a compiler switch). So if assign a generic integer to a Dice_Throw, the Ada compiler performs a run-time test to see if it's in the correct range. Ada code is based on similar things that avoid/catch lot of bugs. Bye, bearophile
Aug 02 2013