digitalmars.D.learn - Tuple poilerplate code
- JG (13/13) Aug 31 2020 Is there anyway to remove the boilerplate code of dealing with
- user1234 (14/27) Aug 31 2020 ---
- JG (4/38) Sep 01 2020 Thanks for your answer. That helps somewhat, however it is still
- Paul Backus (27/34) Sep 01 2020 I like using the following snippet for this kind of thing:
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (23/36) Sep 01 2020 When you know the types, this works:
- WebFreak001 (34/35) Sep 01 2020 Here is some fun with operator overloading and pointers, but I
Is there anyway to remove the boilerplate code of dealing with tuples: I find myself having to write things like this fairly often auto someRandomName = f(...); //where f returns a tuple with two parts auto firstPart = someRandomName[0]; auto secondPart = someRandomName[1]; Is to possible to write something so that the above is essentially equivalent to: assignTuple!(firstPart,secondPart) = f(...); The closest I can produce is using a template mixin so that I would have to write: mixin AssignTuple!(()=>f(...),"firstPart","secondPart");
Aug 31 2020
On Tuesday, 1 September 2020 at 02:08:54 UTC, JG wrote:Is there anyway to remove the boilerplate code of dealing with tuples: I find myself having to write things like this fairly often auto someRandomName = f(...); //where f returns a tuple with two parts auto firstPart = someRandomName[0]; auto secondPart = someRandomName[1]; Is to possible to write something so that the above is essentially equivalent to: assignTuple!(firstPart,secondPart) = f(...); The closest I can produce is using a template mixin so that I would have to write: mixin AssignTuple!(()=>f(...),"firstPart","secondPart");--- void assignTuple(S, T...)(auto ref S s, auto ref T t) { static foreach (i; 0 .. S.length) t[i] = s[i]; } void main() { import std; string a,b; tuple("a", "b").assignTuple(a,b); } ---
Aug 31 2020
On Tuesday, 1 September 2020 at 03:51:10 UTC, user1234 wrote:On Tuesday, 1 September 2020 at 02:08:54 UTC, JG wrote:Thanks for your answer. That helps somewhat, however it is still longer and less clear than one would ideally want. In addition you need to use explicit types.Is there anyway to remove the boilerplate code of dealing with tuples: I find myself having to write things like this fairly often auto someRandomName = f(...); //where f returns a tuple with two parts auto firstPart = someRandomName[0]; auto secondPart = someRandomName[1]; Is to possible to write something so that the above is essentially equivalent to: assignTuple!(firstPart,secondPart) = f(...); The closest I can produce is using a template mixin so that I would have to write: mixin AssignTuple!(()=>f(...),"firstPart","secondPart");--- void assignTuple(S, T...)(auto ref S s, auto ref T t) { static foreach (i; 0 .. S.length) t[i] = s[i]; } void main() { import std; string a,b; tuple("a", "b").assignTuple(a,b); } ---
Sep 01 2020
On Tuesday, 1 September 2020 at 02:08:54 UTC, JG wrote:Is there anyway to remove the boilerplate code of dealing with tuples: I find myself having to write things like this fairly often auto someRandomName = f(...); //where f returns a tuple with two parts auto firstPart = someRandomName[0]; auto secondPart = someRandomName[1];I like using the following snippet for this kind of thing: /// Pass the members of a tuple as arguments to a function template unpack(alias fun) { import std.typecons: isTuple; auto unpack(T)(T args) if (isTuple!T) { return fun(args.expand); } } Usage looks like this: f(...).unpack!((firstPart, secondPart) { // use firstPart and secondPart in here }); It also works very well in range pipelines; for example, auto nums = [1, 2, 3]; auto animals = ["lion", "tiger", "bear"]; zip(nums, animals) .map!(unpack!((num, animal) => animal.repeat(num).joiner(" "))) .each!writeln; ...which prints the output: lion tiger tiger bear bear bear
Sep 01 2020
On Tuesday, 1 September 2020 at 02:08:54 UTC, JG wrote:Is there anyway to remove the boilerplate code of dealing with tuples: I find myself having to write things like this fairly often auto someRandomName = f(...); //where f returns a tuple with two parts auto firstPart = someRandomName[0]; auto secondPart = someRandomName[1]; Is to possible to write something so that the above is essentially equivalent to: assignTuple!(firstPart,secondPart) = f(...); The closest I can produce is using a template mixin so that I would have to write: mixin AssignTuple!(()=>f(...),"firstPart","secondPart");When you know the types, this works: import std.typecons : tuple; import std.meta : AliasSeq; int firstPart; string secondPart; AliasSeq!(firstPart, secondPart) = tuple(1, "foo"); assert(firstPart == 1); assert(secondPart == "foo"); I know Timon Gehr worked on a DIP for improved tuples, which I think would include the syntax `auto (firstPart, secondPart) = tuple(1, "foo");`, but I don't know what's happened to that idea lately. I also feel it's worth pointing out that Paul Backus' code looks elegant when used outside a map as well: tuple(1, "foo").unpack!((i, s) { writeln("i (", typeof(i).stringof, "): ", i, ", s (", typeof(s).stringof, "): ", s); }); Will print: i (int): 1, s (string): foo -- Simen
Sep 01 2020
On Tuesday, 1 September 2020 at 02:08:54 UTC, JG wrote:[...]Here is some fun with operator overloading and pointers, but I don't really like it because it seems unsafe: import std; auto _(T...)(return ref T refs) safe { static struct Assigner(Ptrs...) { disable this(this); private Ptrs ptrs; void opAssign(T)(T v) if (T.expand.length == Ptrs.length) { static foreach (i; 0 .. Ptrs.length) *ptrs[i] = v[i]; } } static Assigner!U assigner(U...)(U v) { return Assigner!U(v); } static string assignerCall(size_t len)() { string ret = "assigner("; static foreach (i; 0 .. len) ret ~= "&refs[" ~ i.stringof ~ "], "; return ret ~ ")"; } return mixin(assignerCall!(T.length)); } void main() { string a, b, c; int x; _(a, b, c, x) = tuple("a", "b", "c", 4); writeln(a, b, c, x); _(a, b) = tuple(b, a); writeln(a, b); }
Sep 01 2020
On Wednesday, 2 September 2020 at 03:52:55 UTC, JG wrote:Thank you all for the interesting suggestions.Still thinking about this from time to time. Other than the suggestions given, this is what I have been playing around with. --------------------------------- import std.stdio; import std.typecons : tuple; mixin template assignTuple(alias vars, alias tupleFunc) { import std.conv : to; auto tmp = tupleFunc(); static foreach (i, var ; vars) { mixin("auto " ~ var ~ " = tmp[" ~ i.to!string ~ "];"); } } auto f(int n) { return tuple(n, n+1, n+2, "A string here"); } void main() { mixin assignTuple!(["x","y","z", "str"],()=>f(3)); writeln(x," ",y," ", z," \'",str,"\'"); } --------------------------------- produces --------------------------------- 3 4 5 'A string here' --------------------------------- I have a few questions: 1. Is the above code "bad" for some reason? 2. Is there a way of "hiding" tmp used in the mixin, so that it is not visible in main?
Sep 18 2020