Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
September 01, 2020 Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
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"); |
September 01, 2020 Re: Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
Posted in reply to JG | 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);
}
---
|
September 01, 2020 Re: Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
Posted in reply to user1234 | On Tuesday, 1 September 2020 at 03:51:10 UTC, user1234 wrote:
> 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);
> }
> ---
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.
|
September 01, 2020 Re: Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
Posted in reply to JG | 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
|
September 01, 2020 Re: Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
Posted in reply to JG | 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
|
September 01, 2020 Re: Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
Posted in reply to JG | 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); } |
September 02, 2020 Re: Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
Posted in reply to WebFreak001 | Thank you all for the interesting suggestions. |
September 19, 2020 Re: Tuple poilerplate code | ||||
---|---|---|---|---|
| ||||
Posted in reply to JG | 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? |
Copyright © 1999-2021 by the D Language Foundation