digitalmars.D.learn - can I generate an enum from a typelist?
- Vlad Levenfeld (62/62) Apr 08 2014 I'm a beginner to D and I have written this awful code:
- Vlad Levenfeld (27/90) Apr 08 2014 After a bit more thought I've managed to eliminate the TypeTuple
- Vlad Levenfeld (11/11) Apr 08 2014 Ok, starting to feel a bit sheepish at this point, that
- Rene Zwanenburg (5/16) Apr 08 2014 Depending on what you're exactly trying to do, you may be able to
- Vlad Levenfeld (6/6) Apr 08 2014 That's exactly what I was looking for. I pulled the Solid,...,etc
- bearophile (4/5) Apr 08 2014 I suggest no space before the bang when you instantiate templates.
- Vlad Levenfeld (3/10) Apr 09 2014 Because it will be more easily confused with a logical not
- monarch_dodra (12/25) Apr 09 2014 Because it's generic D syntax. what's on the right of "!" are
- Frustrated (7/18) Apr 08 2014 You can simply reflect on your nested structs and generate the
I'm a beginner to D and I have written this awful code: struct Layer { // defs alias Types = TypeTuple !(Solid, Gradient, Text, Sprite, Plane); enum Type { solid = staticIndexOf !(Solid, Types), gradient = staticIndexOf !(Gradient, Types), text = staticIndexOf !(Text, Types), sprite = staticIndexOf !(Sprite, Types), plane = staticIndexOf !(Plane, Types), invalid = -1 } struct Solid {...} struct Gradient {...} struct Text {...} struct Sprite {...} struct Plane {...} // data const Type type; union { Solid solid; Gradient gradient; Text text; Sprite sprite; Plane plane; } // ctor disable this (); this (T) (T layer) if (not (staticIndexOf !(T, Types) is (Type.invalid))) { auto type = cast (const Type) staticIndexOf !(T, Types); auto type_name = cast (const) to !string (EnumMembers !Type [type]); mixin ("this."~type_name~"= layer;"); this.type = type; } } So, the layer types are being rewritten 4 times. I anticipate hair pulling and teeth grinding when I come back later to add more layer types (after I've forgotten the implementation details). Ideally, I'd like to just get the names of all the nested structs within the Layer struct and use a template to populate both the enum and the union, but I can't use templates to change the size of a type (so the union is out) and I have no idea how I might lowercase the first letter of each type name in the TypeTuple at compile time (there goes the enum). Is there anything I can do to clean this mess up? Maybe there's at least a way to generate an enum off the union using std.traits.allMembers or something? I've got a feeling that my design kind of sucks anyway, so I'm open to suggestions to take it in completely different direction as well.
Apr 08 2014
On Tuesday, 8 April 2014 at 07:39:29 UTC, Vlad Levenfeld wrote:I'm a beginner to D and I have written this awful code: struct Layer { // defs alias Types = TypeTuple !(Solid, Gradient, Text, Sprite, Plane); enum Type { solid = staticIndexOf !(Solid, Types), gradient = staticIndexOf !(Gradient, Types), text = staticIndexOf !(Text, Types), sprite = staticIndexOf !(Sprite, Types), plane = staticIndexOf !(Plane, Types), invalid = -1 } struct Solid {...} struct Gradient {...} struct Text {...} struct Sprite {...} struct Plane {...} // data const Type type; union { Solid solid; Gradient gradient; Text text; Sprite sprite; Plane plane; } // ctor disable this (); this (T) (T layer) if (not (staticIndexOf !(T, Types) is (Type.invalid))) { auto type = cast (const Type) staticIndexOf !(T, Types); auto type_name = cast (const) to !string (EnumMembers !Type [type]); mixin ("this."~type_name~"= layer;"); this.type = type; } } So, the layer types are being rewritten 4 times. I anticipate hair pulling and teeth grinding when I come back later to add more layer types (after I've forgotten the implementation details). Ideally, I'd like to just get the names of all the nested structs within the Layer struct and use a template to populate both the enum and the union, but I can't use templates to change the size of a type (so the union is out) and I have no idea how I might lowercase the first letter of each type name in the TypeTuple at compile time (there goes the enum). Is there anything I can do to clean this mess up? Maybe there's at least a way to generate an enum off the union using std.traits.allMembers or something? I've got a feeling that my design kind of sucks anyway, so I'm open to suggestions to take it in completely different direction as well.After a bit more thought I've managed to eliminate the TypeTuple and the enum by defining a const TypeInfo member. Also, std.string.toLower apparently works at compile time. Just when I thought D couldn't possible get more 'magic'... Here is my current solution (redundant declarations of Solid... etc omitted) for critique/completeness/posterity/something: // data const TypeInfo type; union { Solid solid; Gradient gradient; Text text; Sprite sprite; Plane plane; } // ctor disable this (); this (T) (T layer) { import std.string: toLower; auto type = cast (const) typeid (T); auto type_name = cast (const) toLower T.stringof); mixin ("this."~type_name~"= layer;"); this.type = type; }
Apr 08 2014
Ok, starting to feel a bit sheepish at this point, that constructor was unnecessarily verbose: this (T) (T layer) { import std.string: toLower; mixin ("this."~toLower (T.stringof)~"= layer;"); this.type = cast (const) typeid (T); } ...is what I have settled on. Sorry for all the noise! There doesn't seem to be a way to edit posts here...
Apr 08 2014
On Tuesday, 8 April 2014 at 08:31:16 UTC, Vlad Levenfeld wrote:Ok, starting to feel a bit sheepish at this point, that constructor was unnecessarily verbose: this (T) (T layer) { import std.string: toLower; mixin ("this."~toLower (T.stringof)~"= layer;"); this.type = cast (const) typeid (T); } ...is what I have settled on.Depending on what you're exactly trying to do, you may be able to simplify your code using Algebraic [1] from std.variant.Sorry for all the noise! There doesn't seem to be a way to edit posts here...Yeah, the forum is actually a web front end for the newsgroup ;)
Apr 08 2014
That's exactly what I was looking for. I pulled the Solid,...,etc definitions out of Layer and replaced the entire Layer definition with this: alias Layer = Algebraic !(Solid, Gradient, Text, Sprite, Plane); and after grepping in the get!(T) method, everything works perfectly. This is a really clean solution, thank you!
Apr 08 2014
Vlad Levenfeld:alias Layer = Algebraic !(Solid, Gradient, Text, Sprite, Plane);I suggest no space before the bang when you instantiate templates. Bye, bearophile
Apr 08 2014
On Wednesday, 9 April 2014 at 00:27:48 UTC, bearophile wrote:Vlad Levenfeld:Because it will be more easily confused with a logical not operator?alias Layer = Algebraic !(Solid, Gradient, Text, Sprite, Plane);I suggest no space before the bang when you instantiate templates. Bye, bearophile
Apr 09 2014
On Wednesday, 9 April 2014 at 07:37:18 UTC, Vlad Levenfeld wrote:On Wednesday, 9 April 2014 at 00:27:48 UTC, bearophile wrote:Because it's generic D syntax. what's on the right of "!" are considered the parameters of what's on the left. The "whole" is considered a "word" of sorts. If you apply a space, it inserts a break in the word, which looks weird. And yes, it does add a bit of confusion (but that's mostly because I've *never* actually seen a space before the parameter specifier "!"). Also, if you've already defined the type tuple "Types", then you can just use that: alias Layer = Algebraic!Types; Short and sweet.Vlad Levenfeld:Because it will be more easily confused with a logical not operator?alias Layer = Algebraic !(Solid, Gradient, Text, Sprite, Plane);I suggest no space before the bang when you instantiate templates. Bye, bearophile
Apr 09 2014
On Tuesday, 8 April 2014 at 08:31:16 UTC, Vlad Levenfeld wrote:Ok, starting to feel a bit sheepish at this point, that constructor was unnecessarily verbose: this (T) (T layer) { import std.string: toLower; mixin ("this."~toLower (T.stringof)~"= layer;"); this.type = cast (const) typeid (T); } ...is what I have settled on. Sorry for all the noise! There doesn't seem to be a way to edit posts here...You can simply reflect on your nested structs and generate the enum from them. No need to duplicate anything. The only thing you have to do is figure out how to determine if a nested struct is part of the enum. If all nested structs of Layer are then it is easy. Else some naming scheme or inheritance needs to be used to distinguish them from others.
Apr 08 2014