<div class="gmail_quote">On Thu, Jul 1, 2010 at 01:13, bearophile <span dir="ltr"><<a href="mailto:bearophileHUGS@lycos.com">bearophileHUGS@lycos.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
I'd like to add five enhancement requests in Bugzilla, related to std.typecons.Tuple. I show them here first for possible comments or critiques.<br></blockquote><div><br>OK, here I go.<br><br>I don't plan to make you like current D tuples, but I'd like to show some facilities the current syntax provide... and some things I discovered while answering this, in case other people reading this didn't know them either.<br>
<br><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
I have seen that std.typecons.Tuple is quite useful, but it misses some very important features. Some features can just be added to it (see for example bug 4381 ) </blockquote><div><br>Yes this one (adding a .length member) seems easy. <br>
<br>just add either<br><br>@property size_t length() { return Types.length; }<br><br>or<br><br>immutable length = Types.length<br><br><br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
and maybe the apply(). But other features can't just be added, they need some syntax and semantic support.<br>
<br>
Some other useful things:<br>
- More integration and usage of Tuple in druntime. For example the associative array property AA.byItem() can yield tuple(key,value) lazily, and AA.items can return a dynamic array of them.<br></blockquote><div><br>I like that, as the range associated to AA is quite naturally a lazy Tuple!(K,V)[]. <br>
opSlice() is not defined for AA, so whe not use it to return a range?<br><br>auto range = aa[]; // lazily produce (K,V) pairs<br><br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
- Some way to reverse the order of the items of a tuple (generating a tuple of different type).<br></blockquote><div><br>I had some fun with this and ideas like this. Inserting elements, rotating tuples, reversing them, etc. Even mapping polymorphic functions on tuples and reducing them, though I don't think these should be part of any standard library.<br>
<br>You can these there:<br><a href="http://svn.dsource.org/projects/dranges/trunk/dranges/docs/tuple2.html">http://svn.dsource.org/projects/dranges/trunk/dranges/docs/tuple2.html</a><br><br><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
- "in" operator for tuples (as for arrays).<br></blockquote><div><br>Yes, and that seems easily implementable. I use this:<br><br>bool contains(U, T...)(Tuple!T tup, U elem)<br>{<br> static if (staticIndexOf!(U,T) == -1)<br>
return false;<br> else<br> {<br> foreach(i, Type; tup.Types)<br> {<br> static if (is(Type == U))<br> if (tup.field[i] == elem) return true;<br> }<br> return false;<br>
}<br>}<br><br>But I now see I could iterate directly by jumping at staticIndexOf(U,T) and if the value is not OK, continuing on the tail. Though on most cases, tuples have only a few elements...<br><br><br><br> <br></div>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
- More tuple-aware functions in Phobos, like a function to build an AA from a range of tuple(key, value).<br></blockquote><div><br>Oh yes.<br> <br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
- Optional: Zip and other pairing ranges to yield tuple (currently for efficiency they yield a pair of pointers. But this breaks abstraction. Using a more common data structure has significant advantages. The compiler can recognize the idiom and in some cases can avoid the creation of the Tuples that Zip produce.<br>
</blockquote><div><br>I don't like the idea of compiler magic, but I do like the idea of having a Zip that uses the standard structure: tuples. Its easier to inferface with other functions this way. The Proxy from phobos zip is good for sorting (which is why Andrei defined it this way, I guess), but it's a pain to use otherwise, because it's a one-of-a-kind struct that cannot be fed to other functions.<br>
<br><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
Tuple unpacking is quite handy (the following syntax is just an syntax-idea, other syntaxes can be used. This syntax is not valid in C, so I think this syntax can be used in D):<br>
<br>
auto foo() {<br>
return tuple(10, "hello");<br>
}<br>
void main() {<br>
(int n, string s) = foo();<br></blockquote><div><br>I also woud like that. While waiting to convince Walter, we can use some poor man alternative like this one:<br><br>void copy(T...)(ref T to, Tuple!T from)<br>{<br>
foreach(i,Type; T)<br> {<br> to[i] = from.field[i];<br> }<br>}<br><br>usage:<br><br>auto t = tuple(1, 3.14, "abc");<br>int i; double d; string s;<br>copy(i,d,s, t);<br><br>otherwise, you can use this:<br>
<br>auto ids = t.expand;<br><br>ids is an instantiated typetuple: you can index it (ids[1]), slice it (ids[0..2]), iterate on it with foreach, etc.<br>The only thing you cannot do is returning it from a function ...<br><br>
I know it's not as good as what you want (where you define and assign you n and s in one go).<br><br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
writeln(n, " ", s);<br>
(n, s) = foo(); // calls is again<br>
int[] arr = [1, 2, 3];<br>
(int a, int b, int c) = arr; // other kind of unpacking<br></blockquote><div><br>I experimented with a struct called RefTuple, that took constructor values by ref and that did the kind of destructuring you present here. I created it with a function called _ (yes, just _).<br>
This gave the following syntax:<br><br>int n; string s;<br>_(n,s) = foo();<br><br><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
------------<br>
<br>
This is the syntax that can be currently used:<br>
<br>
auto foo() {<br>
T1 alpha = computeIt1(...);<br>
T1 alpha = computeIt2(...);<br>
return Tuple!(T1, "alpha", T2, "beta")(alpha, beta);<br>
//return tuple(alpha, beta); // alternative<br>
}<br>
void main() {<br>
auto alpha_beta = foo();<br>
use1(alpha_beta.alpha);<br>
use2(alpha_beta.beta);<br>
use1(alpha_beta.field[0]); // alternative<br>
use2(alpha_beta.field[1]); // alternative<br>
}<br></blockquote><div><br>You can also use ._x:<br><br>use1(alpha_beta._0);<br>use1(alpha_beta._1);<br><br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
------------<br>
<br>
More syntax that can be currently used:<br>
<br>
import std.stdio, std.typecons;<br>
void main() {<br>
int[] arr2 = [tuple(1, 2, 3).tupleof];<br>
writeln(arr2);<br>
}<br>
<br>
But it prints:<br>
1 2 3 1 2 3<br>
Instead of:<br>
[1, 2, 3]<br></blockquote><div><br>Yeah, tupleof return a strange value for tuple. I understood why, but quickly forgot about it. Maybe it's possible to make .tupleof an alias of .expand?<br>(** test, hmm no, doesn't work **)<br>
I personnaly use expand a lot:<br><br>auto t = tuple(1,2,3);<br>int[] arr2 = [t.expand]; // works. <br></div><div><br>I like that to couple tuples and functions:<br><br>void foo(int i, double d, string s) {}<br><br>auto t = tuple(1, 3.14, "abc");<br>
<br>foo(t.expand); // works.<br> <br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
opIndex/opIndexAssign syntax support for tuples:<br>
<br>
auto tup = tuple(10, 20, 30, 40);<br>
writeln(tup[0]);<br>
tup[1] = 5;<br>
int y = tup[2];<br>
tup[3]++;<br>
<br>
<br>
Slice syntax for tuples (currently done with 'Tuple.slice'):<br>
auto tup = tuple(10, 20, 30, 40, 50, 60);<br>
auto part = tup[1 .. 3];<br></blockquote><div><br>Once again, you can use ._x, .field or .expand for that. It's not perfect, but it's not bad either:<br><br>auto t = tuple(1, 3.14, "abc");<br>writeln(tup._0); // writes 1<br>
t._1 = 1.414; // t is now tuple(1, 1.414, "abc")<br>string s = t._2;<br>t._0++; // works<br><br><br>alternative syntax (.field or .expand)<br><br>writeln(t.field[0]);<br>t.field[1] = 1.414;<br>string s = t.field[2];<br>
t.field[0]++;<br><br>And for slicing:<br><br>auto t2 = t.field[1..3]; //but t is an instantiated typetuple (ie, an 'old way' tuple, a (int,string), not a std.typecons.Tuple!(int,string))<br>auto t3 = tuple(t.field[1..3]); t3 is a bone fide Tuple!(double, string)<br>
<br>Man, typetuples are almost perfect... If only they could once again be returned from functions...<br> <br><br><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
<br>
The type of tuple elements can differ, so the index must be known at compile-time, just as with tupleof[].<br>
<br>
A possible way to implement it (currently this can't be used):<br>
alias this.tupleof[0..$] this;<br></blockquote><div><br><br>Tuple code list bug 2800 as a blocker for this.<br><br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
==========================================<br>
<br>
Title: [Better tuples] (static) foreach on tuple items<br>
<br>
This is one of the tuple enhancement requests. See bug xxxx for an introduction.<br>
<br>
auto tup = tuple(10, 20, 30);<br>
static foreach (item; tup)<br>
writeln(item);<br></blockquote><div><br>So, you can use:<br><br>foreach(index, item; tup.expand) <br> writeln(item);<br><br><br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
(apply => smelting a tuple to give it to a function)<br>
<br>
<br>
A possible usage in D:<br>
<br>
void foo(T1, T2)(T1 x, T2 y) {<br>
writeln(x, " ", y);<br>
}<br>
void main() {<br>
auto tuple1 = tuple(1, 2);<br>
apply(&foo!(tuple1[0].typeof, tuple1[1].typeof), tuple1);<br>
auto tuple2 = tuple(1, 2, 3);<br>
apply(&foo!(tuple2[0].typeof, tuple2[1].typeof), tuple2[0..2]);<br>
}<br>
<br></blockquote><div><br>Wheww.<br>OK, at the risk of repeating myself, why not like this?<br><br>void main() {<br> auto t = tuple(1,"abc");<br> foo(t.expand); <br> auto t2 = tuple(3.14, 1, "abc");<br>
foo(t2.field[1..$]);<br>}<br><br>It's not that bad, no?<br><br><br>Philippe<br><br></div></div>