digitalmars.D.learn - switch to member
- Ignacious (21/21) Jan 13 2017 When doing common functionality for a switch, is there any way to
- Nicholas Wilson (21/43) Jan 13 2017 if `q` is the only data structure that you are wanting to do
- Meta (5/20) Jan 14 2017 IMO this is massive overkill to save some typing. To the OP, it's
- =?UTF-8?Q?Ali_=c3=87ehreli?= (3/22) Jan 13 2017 Sounds like opDispatch may be useful.
- Marc =?UTF-8?B?U2Now7x0eg==?= (34/34) Jan 14 2017 You can utilize a little-known `switch` syntax trick in
- Ivan Kazmenko (3/8) Jan 14 2017 That looks concise. Perhaps enum Which can also be automatically
- Ignacious (6/40) Jan 14 2017 Cool, pretty straightforward and somewhat easy to use. I suppose
- Ivan Kazmenko (17/30) Jan 14 2017 Do you mean that verbatim? Or are the case values strings, like:
When doing common functionality for a switch, is there any way to optimize: switch(x) { case X: q.X = e; break; case Y: q.Y = e; break etc... } e is basically a value that, depending on the what kind(x), we assign it to a field in q. The name of the field and the case label are identical(in fact, it wouldn't hurt to do it either automatically(if x's enum name, if exists, matches a field, auto assign) or create the field in the class q automatically if the label matches a certain range or set). Basically the idea is to avoid duplicating a lot of code. I imagine one could write a string mixin that generates the cases and assignments but I'm hoping for a more elegant solution.
Jan 13 2017
On Saturday, 14 January 2017 at 03:20:24 UTC, Ignacious wrote:When doing common functionality for a switch, is there any way to optimize: switch(x) { case X: q.X = e; break; case Y: q.Y = e; break etc... } e is basically a value that, depending on the what kind(x), we assign it to a field in q. The name of the field and the case label are identical(in fact, it wouldn't hurt to do it either automatically(if x's enum name, if exists, matches a field, auto assign) or create the field in the class q automatically if the label matches a certain range or set). Basically the idea is to avoid duplicating a lot of code. I imagine one could write a string mixin that generates the cases and assignments but I'm hoping for a more elegant solution.if `q` is the only data structure that you are wanting to do this for (or a 1:1 mapping for enum and type) then you can make the enumeration values of x equal to the offsetof of q. e.g. where typeof(q) == Q enum XX { X = Q.X.offsetof, Y = Q.Y.offsetof //ect. } and then *(cast(void*)(this) + x) = e; //if inside struct/class or *(cast(void*)(q) + x) = e; // if outside Unfortunately this loses you ` safe`ty, but as long as you trust the value of x then it should be safe to ` trusted` that code. If you are trying to avoid code duplication the enum declaration of X could also be done with a string mixin.
Jan 13 2017
On Saturday, 14 January 2017 at 05:29:49 UTC, Nicholas Wilson wrote:enum XX { X = Q.X.offsetof, Y = Q.Y.offsetof //ect. } and then *(cast(void*)(this) + x) = e; //if inside struct/class or *(cast(void*)(q) + x) = e; // if outside Unfortunately this loses you ` safe`ty, but as long as you trust the value of x then it should be safe to ` trusted` that code. If you are trying to avoid code duplication the enum declaration of X could also be done with a string mixin.IMO this is massive overkill to save some typing. To the OP, it's not really worth it to go to so much trouble. Just write some slightly duplicated code and move on.
Jan 14 2017
On Saturday, 14 January 2017 at 08:30:04 UTC, Meta wrote:On Saturday, 14 January 2017 at 05:29:49 UTC, Nicholas Wilson wrote:Go join the Nazi Youth group, you OSS Sympathizer!enum XX { X = Q.X.offsetof, Y = Q.Y.offsetof //ect. } and then *(cast(void*)(this) + x) = e; //if inside struct/class or *(cast(void*)(q) + x) = e; // if outside Unfortunately this loses you ` safe`ty, but as long as you trust the value of x then it should be safe to ` trusted` that code. If you are trying to avoid code duplication the enum declaration of X could also be done with a string mixin.IMO this is massive overkill to save some typing. To the OP, it's not really worth it to go to so much trouble. Just write some slightly duplicated code and move on.
Jan 14 2017
On Saturday, 14 January 2017 at 16:05:33 UTC, Ignacious wrote:Go join the Nazi Youth group, you OSS Sympathizer!What?
Jan 14 2017
On 01/13/2017 07:20 PM, Ignacious wrote:When doing common functionality for a switch, is there any way to optimize: switch(x) { case X: q.X = e; break; case Y: q.Y = e; break etc... } e is basically a value that, depending on the what kind(x), we assign it to a field in q. The name of the field and the case label are identical(in fact, it wouldn't hurt to do it either automatically(if x's enum name, if exists, matches a field, auto assign) or create the field in the class q automatically if the label matches a certain range or set). Basically the idea is to avoid duplicating a lot of code. I imagine one could write a string mixin that generates the cases and assignments but I'm hoping for a more elegant solution.Sounds like opDispatch may be useful. Ali
Jan 13 2017
You can utilize a little-known `switch` syntax trick in combination with `foreach`. Because a `foreach` over tuples is unrolled at compile time, it works even if your fields don't have exactly the same types: -------------------------------------------------------------- struct Foo { int x, y; long a, b, c; short i, j, k; } enum Which { x, y, a, b, c, i, j, k, } void assignValue(ref Foo q, Which member, short e) { import std.traits : EnumMembers; import std.conv : to; final switch(member) { // foreach over a tuple is unrolled at compile time foreach(w; EnumMembers!Which) { case w: // expands to: q.x, q.y, ... mixin("q." ~ w.to!string) = e; break; } } } void main() { import std.stdio : writeln; Foo q; writeln("before: ", q); assignValue(q, Which.a, 42); assignValue(q, Which.x, 1); writeln("after: ", q); }
Jan 14 2017
On Saturday, 14 January 2017 at 11:32:10 UTC, Marc Schütz wrote:You can utilize a little-known `switch` syntax trick in combination with `foreach`. Because a `foreach` over tuples is unrolled at compile time, it works even if your fields don't have exactly the same types: <snip>That looks concise. Perhaps enum Which can also be automatically filled by __traits (allMembers) or std.traits.Fields if needed.
Jan 14 2017
On Saturday, 14 January 2017 at 11:32:10 UTC, Marc Schütz wrote:You can utilize a little-known `switch` syntax trick in combination with `foreach`. Because a `foreach` over tuples is unrolled at compile time, it works even if your fields don't have exactly the same types: -------------------------------------------------------------- struct Foo { int x, y; long a, b, c; short i, j, k; } enum Which { x, y, a, b, c, i, j, k, } void assignValue(ref Foo q, Which member, short e) { import std.traits : EnumMembers; import std.conv : to; final switch(member) { // foreach over a tuple is unrolled at compile time foreach(w; EnumMembers!Which) { case w: // expands to: q.x, q.y, ... mixin("q." ~ w.to!string) = e; break; } } } void main() { import std.stdio : writeln; Foo q; writeln("before: ", q); assignValue(q, Which.a, 42); assignValue(q, Which.x, 1); writeln("after: ", q); }Cool, pretty straightforward and somewhat easy to use. I suppose it might be easier to mark the enum members with an attribute though and use that rather than having two enums? I didn't know about the foreach in the switch, cool idea! Thanks.
Jan 14 2017
On Saturday, 14 January 2017 at 03:20:24 UTC, Ignacious wrote:switch(x) { case X: q.X = e; break; case Y: q.Y = e; break etc... }Do you mean that verbatim? Or are the case values strings, like: switch(x) { case "foo": q.foo = e; break; case "bar": q.bar = e; break }I imagine one could write a string mixin that generates the cases and assignments but I'm hoping for a more elegant solution.In any case, I also can imagine a mixin answer, but not much better. Unless you want to actually look at the broader picture and maybe redesign the surrounding code to somehow cleverly get rid of the switch altogether. The question as it is however doesn't give the context to make it possible. Ivan Kazmenko.
Jan 14 2017