<div class="gmail_quote">On Thu, Jul 1, 2010 at 01:13, bearophile <span dir="ltr">&lt;<a href="mailto:bearophileHUGS@lycos.com">bearophileHUGS@lycos.com</a>&gt;</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&#39;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&#39;t plan to make you like current D tuples, but I&#39;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&#39;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&#39;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&#39;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;">

- &quot;in&quot; 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&#39;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&#39;s a pain to use otherwise, because it&#39;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, &quot;hello&quot;);<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, &quot;abc&quot;);<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&#39;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, &quot; &quot;, 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, &quot;alpha&quot;, T2, &quot;beta&quot;)(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&#39;s possible to make .tupleof an alias of .expand?<br>(** test, hmm no, doesn&#39;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, &quot;abc&quot;);<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 &#39;Tuple.slice&#39;):<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&#39;s not perfect, but it&#39;s not bad either:<br><br>auto t = tuple(1, 3.14, &quot;abc&quot;);<br>writeln(tup._0); // writes 1<br>
t._1 = 1.414;       // t is now tuple(1, 1.414, &quot;abc&quot;)<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 &#39;old way&#39; 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&#39;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 =&gt; 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, &quot; &quot;, y);<br>
}<br>
void main() {<br>
    auto tuple1 = tuple(1, 2);<br>
    apply(&amp;foo!(tuple1[0].typeof, tuple1[1].typeof), tuple1);<br>
    auto tuple2 = tuple(1, 2, 3);<br>
    apply(&amp;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,&quot;abc&quot;);<br>    foo(t.expand); <br>    auto t2 = tuple(3.14, 1, &quot;abc&quot;);<br>
    foo(t2.field[1..$]);<br>}<br><br>It&#39;s not that bad, no?<br><br><br>Philippe<br><br></div></div>