digitalmars.D.learn - How do I generate `setX` methods for all private mutable variables in
- Ki Rill (26/26) Jun 05 2023 How do I generate `setX` methods for all private mutable
- Basile B. (38/65) Jun 05 2023 You need to put an user attribute on the fieldd then to use
- Basile B. (33/38) Jun 05 2023 By the way...an other solution is to use
- Steven Schveighoffer (12/49) Jun 06 2023 Ugh, don't do it that way. Always give opDispatch a template constraint
- Basile B. (5/19) Jun 06 2023 yeah I know that opDispatch is disliked because it is tried in a
- =?UTF-8?Q?Ali_=c3=87ehreli?= (7/9) Jun 06 2023 opover.
- Paul Backus (29/49) Jun 05 2023 Is there a reason you can't just make these fields `public`?
- Basile B. (13/14) Jun 06 2023 My bet is that OP actually wants to generate something like
- Basile B. (13/14) Jun 06 2023 My bet is that OP actually wants to generate something like
- cc (29/31) Jun 05 2023 ```d
How do I generate `setX` methods for all private mutable variables in my class? Do I need to use `__traits`? I need this for my [tiny-svg](https://github.com/rillki/tiny-svg) project to generate `setX` methods for all Shapes. Example: ```D class Rectangle { private immutable ...; private Color fillColor; private Color strokeColor; private uint strokeWidth; this(int x, int y) {...} mixin(???); // I need this: Rectangle setFillColor(Color color) {...} Rectangle setStrokeColor(Color color) {...} Rectangle setStrokeWidth(uint color) {...} } ``` Usage: ```D new Rectangle(10, 10) .setFillColor(Colors.white) .setStrokeColor(Colors.black) .setStrokeWidth(3); ```
Jun 05 2023
On Monday, 5 June 2023 at 13:57:20 UTC, Ki Rill wrote:How do I generate `setX` methods for all private mutable variables in my class? Do I need to use `__traits`? I need this for my [tiny-svg](https://github.com/rillki/tiny-svg) project to generate `setX` methods for all Shapes. Example: ```D class Rectangle { private immutable ...; private Color fillColor; private Color strokeColor; private uint strokeWidth; this(int x, int y) {...} mixin(???); // I need this: Rectangle setFillColor(Color color) {...} Rectangle setStrokeColor(Color color) {...} Rectangle setStrokeWidth(uint color) {...} } ``` Usage: ```D new Rectangle(10, 10) .setFillColor(Colors.white) .setStrokeColor(Colors.black) .setStrokeWidth(3); ```You need to put an user attribute on the fieldd then to use static introspection to generate the setters. Very basically that works like that ```d enum Set; class Color {} auto generateSetters(T)() { string result; import std.traits; static foreach (m; __traits(allMembers, T)) {{ alias member = __traits(getMember, T, m); static if (hasUDA!(member, Set)) result ~= "void set" ~ m ~ "(" ~ typeof(member).stringof ~ "){}\n"; }} return result; } class Rectangle { Set private Color fillColor; Set private Color strokeColor; Set private uint strokeWidth; mixin(generateSetters!(Rectangle)()); } void main() { with (new Rectangle) { setstrokeWidth(0); setstrokeColor(null); setfillColor(null); } } ``` although I did not spent time on the setter body... I suppose the question was more about the metprogramming technic, and that you don't want a pre-mashed solution ;)
Jun 05 2023
On Monday, 5 June 2023 at 15:13:43 UTC, Basile B. wrote:On Monday, 5 June 2023 at 13:57:20 UTC, Ki Rill wrote:By the way...an other solution is to use [opDispatch](https://dlang.org/spec/operatoroverloading.html#dispatch): ```d class Color {} class Rectangle { private Color fillColor; private Color strokeColor; private uint strokeWidth; auto opDispatch(string member, T)(auto ref T t) { static if (member == "setStrokeWidth") {} else static if (member == "setStrokeColor") {} else static if (member == "setFillColor") {} else static assert(0, "cannot set " ~ member); return this; } } void main() { (new Rectangle) .setStrokeWidth(0) .setStrokeColor(null) .setFillColor(null); } ``` Sure the first solution takes advantage of D features but to `property`, etc.) On top of that I tend to prefer the later solution because self-introspection based on `__traits` has corner issues, especially when typecons-like structures are used for the members (e.g sumtype, nullable, etc.).How do I generate `setX` methods for all private mutablealthough I did not spent time on the setter body... I suppose the question was more about the metprogramming technic, and that you don't want a pre-mashed solution ;)
Jun 05 2023
On 6/5/23 11:33 AM, Basile B. wrote:On Monday, 5 June 2023 at 15:13:43 UTC, Basile B. wrote:Ugh, don't do it that way. Always give opDispatch a template constraint or it will suck to use. Also, given the problem constraints, you can build the method automatically using the string. ```d auto opDispatch(string member, T)(auto ref T t) if(member.startsWith("set")) { mixin(toLower(m[3]), m[4 .. $], " = t;"); } ``` -SteveOn Monday, 5 June 2023 at 13:57:20 UTC, Ki Rill wrote:By the way...an other solution is to use [opDispatch](https://dlang.org/spec/operatoroverloading.html#dispatch): ```d class Color {} class Rectangle { private Color fillColor; private Color strokeColor; private uint strokeWidth; auto opDispatch(string member, T)(auto ref T t) { static if (member == "setStrokeWidth") {} else static if (member == "setStrokeColor") {} else static if (member == "setFillColor") {} else static assert(0, "cannot set " ~ member); return this; } } void main() { (new Rectangle) .setStrokeWidth(0) .setStrokeColor(null) .setFillColor(null); } ```How do I generate `setX` methods for all private mutablealthough I did not spent time on the setter body... I suppose the question was more about the metprogramming technic, and that you don't want a pre-mashed solution ;)
Jun 06 2023
On Tuesday, 6 June 2023 at 14:23:59 UTC, Steven Schveighoffer wrote:On 6/5/23 11:33 AM, Basile B. wrote:yeah I know that opDispatch is disliked because it is tried in a SFINAE fashion, as citicized by Adam. But on the other side it's the best opover.[...]Ugh, don't do it that way. Always give opDispatch a template constraint or it will suck to use. Also, given the problem constraints, you can build the method automatically using the string. ```d auto opDispatch(string member, T)(auto ref T t) if(member.startsWith("set")) { mixin(toLower(m[3]), m[4 .. $], " = t;"); } ``` -Steve
Jun 06 2023
On 6/6/23 09:13, Basile B. wrote:yeah I know that opDispatch is disliked because it is tried in a SFINAE fashion, as citicized by Adam. But on the other side it's the bestopover. I like how it helped in my current project: user.someShellCommand("-foo", "-bar"); opDispatch makes a command string, passes it to executeShell, takes care of the return code and dumps its output if there was an error. Ali
Jun 06 2023
On Monday, 5 June 2023 at 13:57:20 UTC, Ki Rill wrote:How do I generate `setX` methods for all private mutable variables in my class? Do I need to use `__traits`? I need this for my [tiny-svg](https://github.com/rillki/tiny-svg) project to generate `setX` methods for all Shapes. Example: ```D class Rectangle { private immutable ...; private Color fillColor; private Color strokeColor; private uint strokeWidth; this(int x, int y) {...} mixin(???); // I need this: Rectangle setFillColor(Color color) {...} Rectangle setStrokeColor(Color color) {...} Rectangle setStrokeWidth(uint color) {...} } ```Is there a reason you can't just make these fields `public`? D supports property accessors, so you can always go back and make them `private` later on if it turns out you need to. For example: ```d // Before class MyClass1 { public int data; } void example1(MyClass1 c) { c.data = 123; // set int n = c.data; // get } // After class MyClass2 { private int data_; int data() { return data; } void data(int value) { data = value; } } void example2(MyClass2 c) { // Usage is exactly the same c.data = 123; // set int n = c.data; // get } ```
Jun 05 2023
On Monday, 5 June 2023 at 15:28:34 UTC, Paul Backus wrote:Is there a reason you can't just make these fields `public`?My bet is that OP actually wants to generate something like ```d void setStrokeWidth(uint value) { if (value = strokeWidth) return; strokeWidth = value; redraw(); // or maybe... // needRedraw = true; } ``` that's a common pattern in 2D graphics libraries
Jun 06 2023
On Monday, 5 June 2023 at 15:28:34 UTC, Paul Backus wrote:Is there a reason you can't just make these fields `public`?My bet is that OP actually wants to generate something like ```d void setStrokeWidth(uint value) { if (value = strokeWidth) return; strokeWidth = value; redraw(); // or maybe... // needRedraw = true; } ``` that's a common pattern in 2D graphic libraries.
Jun 06 2023
On Monday, 5 June 2023 at 13:57:20 UTC, Ki Rill wrote:How do I generate `setX` methods for all private mutable variables in my class? Do I need to use `__traits`?```d mixin template GenerateSetters() { static foreach (idx, field; typeof(this).tupleof) static if (__traits(getVisibility,field) == "private") { mixin(q{ void %SETTER(typeof(this.tupleof[idx]) _) { %NAME = _; } } .replace("%NAME", field.stringof) .replace("%SETTER", "set"~toUpper(field.stringof[0..1]) ~ field.stringof[1..$]) ); } } class Rectangle { private Color fillColor; private Color strokeColor; private uint strokeWidth; this(int x, int y) {} mixin GenerateSetters; } void main() { auto rect = new Rectangle(0, 0); rect.setStrokeWidth(4); assert(rect.strokeWidth == 4); } ```
Jun 05 2023
On Monday, 5 June 2023 at 18:54:30 UTC, cc wrote:On Monday, 5 June 2023 at 13:57:20 UTC, Ki Rill wrote:Thank you! That is exactly what I needed. Although another solution provided by Basile B. using attributes opens a door for other posibilities... I don't usually use metaprogramming or code generation much, this is an eye-opening experience.How do I generate `setX` methods for all private mutable variables in my class? Do I need to use `__traits`?```d mixin template GenerateSetters() { static foreach (idx, field; typeof(this).tupleof) static if (__traits(getVisibility,field) == "private") { mixin(q{ void %SETTER(typeof(this.tupleof[idx]) _) { %NAME = _; } } .replace("%NAME", field.stringof) .replace("%SETTER", "set"~toUpper(field.stringof[0..1]) ~ field.stringof[1..$]) ); } } class Rectangle { private Color fillColor; private Color strokeColor; private uint strokeWidth; this(int x, int y) {} mixin GenerateSetters; } void main() { auto rect = new Rectangle(0, 0); rect.setStrokeWidth(4); assert(rect.strokeWidth == 4); } ```
Jun 05 2023
On Monday, 5 June 2023 at 18:54:30 UTC, cc wrote:[...]Is there a way to check for mutability as well? I have both immutable and mutable fields. I would like to generate setters for mutable fields only.
Jun 06 2023
On Tuesday, 6 June 2023 at 21:49:58 UTC, Ki Rill wrote:On Monday, 5 June 2023 at 18:54:30 UTC, cc wrote:that's why a user attribute on the field is somewhat better than very complex introspection. It justs tells you "for that member do that".[...]Is there a way to check for mutability as well? I have both immutable and mutable fields. I would like to generate setters for mutable fields only.
Jun 06 2023