digitalmars.D.learn - What is the "right" way to create a generic type getter (and setter) ?
- James Blachly (50/50) Mar 14 2018 For context, please keep in mind I am coming from a python
- ag0aep6g (31/78) Mar 14 2018 So you've got a large struct like this (right?):
- James Blachly (9/32) Mar 15 2018 Thanks - to!string certainly seems to be a good option in this
- Cym13 (23/60) Mar 15 2018 If you're comming from python you may appreciate that you don't
For context, please keep in mind I am coming from a python background, but am very much enjoying strong typing, although it is taking some significant adjustment. Suppose I have a struct (which is really a memory map of a data file I am reading in) with too many data members to reasonably code getters/setters for by hand. I wish to either retrieve individual values or set individual values, which could be numeric, boolean, or string, from the command line, à la: $ prog -i inputfile.bin get field_name; (prints "300" or "false" or "Welcome to the jungle") $ prog -i inputfile.bin set some_field:9000 $ prog -i inputfile.bin set other_field:Whatever_String Each field itself is strongly typed, for what that's worth. Approaches I have considered and implemented in part are: * templated getter (T get(T)(string field) {...}) but this approach requires knowledge of field types which I cannot reasonably expect to know at runtime(?) * modification to the above whereby I could have an AA holding type information for each field, generated by static foreach {mixin ...}, although I cannot get this to work as my struct's static constructor complains (rightly) that it cannot work without knowing 'this' at compile time. Code: `mixin("field_types[\"" ~ prop ~ "\"] = typeid(this." ~ prop ~ ");");` Is there another __trait I am missing that will give me the type of the struct member without requiring an instance of the struct? I did manage to use metaprogramming inside my templated get function to handle numeric values, which was fascinating (although this is probably ugly code and it required a large enum array FIELDS): ``` GetterSwitch: switch (field) { static foreach(prop; FIELDS ) { mixin("case \"" ~ prop ~ "\": val = this." ~ prop ~ "; break GetterSwitch;"); } default: val = 0; assert(0); // This is to prevent subtle bugs, but I need a better error handler } ``` Any pointers / design patterns on this particular type of problem class would be greatly appreciated. (Sidenote, I realize I could probably use the witchcraft library, but I am also using this as exercise to learn D beyond the basics). Thanks in advance James
Mar 14 2018
On 03/14/2018 11:13 PM, James Blachly wrote:Suppose I have a struct (which is really a memory map of a data file I am reading in) with too many data members to reasonably code getters/setters for by hand. I wish to either retrieve individual values or set individual values, which could be numeric, boolean, or string, from the command line, à la: $ prog -i inputfile.bin get field_name; (prints "300" or "false" or "Welcome to the jungle") $ prog -i inputfile.bin set some_field:9000 $ prog -i inputfile.bin set other_field:Whatever_String Each field itself is strongly typed, for what that's worth.So you've got a large struct like this (right?): ---- struct S { int some_field; string other_field; /* ... more fields with arbitrary types ... */ } ----Approaches I have considered and implemented in part are: * templated getter (T get(T)(string field) {...}) but this approach requires knowledge of field types which I cannot reasonably expect to know at runtime(?)The return type needs to be known at compile time, but `field` is passed at run time. Can't work.* modification to the above whereby I could have an AA holding type information for each field, generated by static foreach {mixin ...}, although I cannot get this to work as my struct's static constructor complains (rightly) that it cannot work without knowing 'this' at compile time. Code: `mixin("field_types[\"" ~ prop ~ "\"] = typeid(this." ~ prop ~ ");");` Is there another __trait I am missing that will give me the type of the struct member without requiring an instance of the struct?You could use `typeid(typeof(this." ~ prop ~ "))`. But you can't use a run-time TypeInfo as a return type. So I don't think this gets you anywhere.I did manage to use metaprogramming inside my templated get function to handle numeric values, which was fascinating (although this is probably ugly code and it required a large enum array FIELDS): ``` GetterSwitch: switch (field) { static foreach(prop; FIELDS ) { mixin("case \"" ~ prop ~ "\": val = this." ~ prop ~ "; break GetterSwitch;"); } default: val = 0; assert(0); // This is to prevent subtle bugs, but I need a better error handler } ```You can probably get around the (manually maintained?) `FIELDS` array with `.tupleof` or something similar: ---- static foreach (i, f; S.tupleof) { case __traits(identifier, f): } ----Any pointers / design patterns on this particular type of problem class would be greatly appreciated. (Sidenote, I realize I could probably use the witchcraft library, but I am also using this as exercise to learn D beyond the basics).You simply cannot have a method that returns different types based on a run-time value. You could possibly return a std.variant.Variant. But if the goal is just to print the value to the screen, all you need is a string. So the signature would be `string get(string field)`. And for the implementation you could use `.tupleof` to iterate over all fields, and then return `f.to!string`. `set` can be done similarly. Take two `string`s: the field name, and the value. `static foreach` over all fields. On a match, convert the given value string to the type of the field that matched.
Mar 14 2018
On Wednesday, 14 March 2018 at 22:58:25 UTC, ag0aep6g wrote:You can probably get around the (manually maintained?) `FIELDS` array with `.tupleof` or something similar: ---- static foreach (i, f; S.tupleof) { case __traits(identifier, f): } ----Thanks - to!string certainly seems to be a good option in this case (CLI) and I was definitely overthinking this part, perhaps because I was trying to write everything as generically / extensibly as possible (for example, to use the same framework but with a GUI or web front end, for example). I would still think an AA mapping (string) field name to a type would be useful and will see if I can construct it as a mixin using typeof(Struct.member) somehow.Any pointers / design patterns on this particular type of problem class would be greatly appreciated. (Sidenote, I realize I could probably use the witchcraft library, but I am also using this as exercise to learn D beyond the basics).You simply cannot have a method that returns different types based on a run-time value. You could possibly return a std.variant.Variant. But if the goal is just to print the value to the screen, all you need is a string. So the signature would be `string get(string field)`. And for the implementation you could use `.tupleof` to iterate over all fields, and then return `f.to!string`. `set` can be done similarly. Take two `string`s: the field name, and the value. `static foreach` over all fields. On a match, convert the given value string to the type of the field that matched.
Mar 15 2018
On Thursday, 15 March 2018 at 15:48:52 UTC, James Blachly wrote:On Wednesday, 14 March 2018 at 22:58:25 UTC, ag0aep6g wrote:If you're comming from python you may appreciate that you don't need getter/setters in D either. Just as you have property in python which allows you to change at any time from a simple attribute to a method (be it reading or writing) you have a property syntax in D: struct S { int a; int _b; auto b() { return _b; } void b(int val) { _b = val; } } void main(string[] args) { S s; s.a = 24; writeln(s.a); s.b = 42; writeln(s.b); }You can probably get around the (manually maintained?) `FIELDS` array with `.tupleof` or something similar: ---- static foreach (i, f; S.tupleof) { case __traits(identifier, f): } ----Thanks - to!string certainly seems to be a good option in this case (CLI) and I was definitely overthinking this part, perhaps because I was trying to write everything as generically / extensibly as possible (for example, to use the same framework but with a GUI or web front end, for example). I would still think an AA mapping (string) field name to a type would be useful and will see if I can construct it as a mixin using typeof(Struct.member) somehow.Any pointers / design patterns on this particular type of problem class would be greatly appreciated. (Sidenote, I realize I could probably use the witchcraft library, but I am also using this as exercise to learn D beyond the basics).You simply cannot have a method that returns different types based on a run-time value. You could possibly return a std.variant.Variant. But if the goal is just to print the value to the screen, all you need is a string. So the signature would be `string get(string field)`. And for the implementation you could use `.tupleof` to iterate over all fields, and then return `f.to!string`. `set` can be done similarly. Take two `string`s: the field name, and the value. `static foreach` over all fields. On a match, convert the given value string to the type of the field that matched.
Mar 15 2018