www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Better tuples

reply bearophile <bearophileHUGS lycos.com> writes:
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.

==========================================

Title: [Better tuples] Better tuples

(In this bug report I talk about something similar to std.typecons.Tuple. A
problem with the "tuple" name: structs have a "tupleof" field, but it returns
something quite different from std.typecons.Tuple. This name clash must be
addressed somehow to avoid confusion of newbie D programmers.)

Some languages as Python show that good tuples (inhomogeneous sequences of
values of arbitrary types, in D they are statically typed) are very handy, they
help a lot in high-level coding.

Some syntactic support can make tuple usage natural, easy and widespread in D
programs written by all people, even newbies. But the lack of such syntax can
keep them a library feature used only by few programmers and makes impossible
some very useful tuples usage patterns. From my experience I think that in a
language as D that allows operator overloading built-in tuples are more useful
than built-in associative arrays (the main advantage of built-in associative
arrays are their type literals that enjoy type inference).

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 ) and maybe the apply(). But other features can't just be added, they need
some syntax and semantic support.

Some other useful things:
- 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.
- Some way to reverse the order of the items of a tuple (generating a tuple of
different type).
- "in" operator for tuples (as for arrays).
- More tuple-aware functions in Phobos, like a function to build an AA from a
range of tuple(key, value).
- 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.

------------

See the enhancement requests: bug 4381 , bug xxxx , bug xxxx , bug xxxx , bug
xxxx , bug xxxx

(This bug report will have dependencies on other six but reports.)
(I will append to bug 4381 a reference to this bug.)

==========================================

Title: [Better tuples] Tuple unpacking

This is one of the tuple enhancement requests. See bug xxxx for an introduction.

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):

auto foo() {
    return tuple(10, "hello");
}
void main() {
    (int n, string s) = foo();
    writeln(n, " ", s);
    (n, s) = foo(); // calls is again
    int[] arr = [1, 2, 3];
    (int a, int b, int c) = arr; // other kind of unpacking
    int2[] arr2 = tuple(1, 2, 3);
    (auto n2, auto s2) = foo(); // calls is again
}

------------

This is the syntax that can be currently used:

auto foo() {
    T1 alpha = computeIt1(...);
    T1 alpha = computeIt2(...);
    return Tuple!(T1, "alpha", T2, "beta")(alpha, beta);
    //return tuple(alpha, beta); // alternative
}
void main() {
    auto alpha_beta = foo();
    use1(alpha_beta.alpha);
    use2(alpha_beta.beta);
    use1(alpha_beta.field[0]); // alternative
    use2(alpha_beta.field[1]);  // alternative    
}

------------

More syntax that can be currently used:

import std.stdio, std.typecons;
void main() {
    int[] arr2 = [tuple(1, 2, 3).tupleof];
    writeln(arr2);
}

But it prints:
1 2 3 1 2 3
Instead of:
[1, 2, 3]

------------

Optional features, more advanced, that can be added later if they are seen
worth it. They are inspired by Python 2.x and 3.x syntax.

Nested unpacking:

auto foo() {
  return tuple(10, tuple("hello", 1.5));
}
void main() {
  (int i, (string s, double d)) = foo();
}



Python 3.x supports a partial tuple unpacking (here 'rest' will contain the
tuple ("hello", 1.5) ):

def bar():
  return (10, "hello", 1.5)
i, *rest = foo()

But I don't know if this is worth adding to D.

==========================================

Title: [Better tuples] [] syntax support for tuples

This is one of the tuple enhancement requests. See bug xxxx for an introduction.

opIndex/opIndexAssign syntax support for tuples:

auto tup = tuple(10, 20, 30, 40);
writeln(tup[0]);
tup[1] = 5;
int y = tup[2];
tup[3]++;


Slice syntax for tuples (currently done with 'Tuple.slice'):
auto tup = tuple(10, 20, 30, 40, 50, 60);
auto part = tup[1 .. 3];


The type of tuple elements can differ, so the index must be known at
compile-time, just as with tupleof[].

A possible way to implement it (currently this can't be used):
alias this.tupleof[0..$] this;

==========================================

Title: [Better tuples] (static) foreach on tuple items

This is one of the tuple enhancement requests. See bug xxxx for an introduction.

auto tup = tuple(10, 20, 30);
static foreach (item; tup)
    writeln(item);


See also bug 4085


Note: in dmd v2.047 this prints all fields twice:

foreach (item; tup.tupleof)
    writeln(item);

==========================================

Title: [Better tuples] Apply with tuples

This is one of the tuple enhancement requests. See bug xxxx for an introduction.

Apply functionality is quite useful, as shown by this small Python program that
prints "1, 2":

def foo(x, y):
    print x, y
tuple1 = (1, 2)
foo(*tuple1)


That star syntax of Python is equivalent to this, that works still in Python
2.x:

def foo(x, y):
    print x, y
tuple1 = (1, 2)
apply(foo, tuple1)

The star syntax can't be used in D, but a good apply() function can be useful
in D too.


A possible usage in D:

void foo(T1, T2)(T1 x, T2 y) {
    writeln(x, " ", y);
}
void main() {
    auto tuple1 = tuple(1, 2);
    apply(&foo!(tuple1[0].typeof, tuple1[1].typeof), tuple1);
    auto tuple2 = tuple(1, 2, 3);
    apply(&foo!(tuple2[0].typeof, tuple2[1].typeof), tuple2[0..2]);
}

==========================================

Bye,
bearophile
Jun 30 2010
next sibling parent reply Eric Poggel <dnewsgroup yage3d.net> writes:
On 6/30/2010 7:13 PM, bearophile wrote:
 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.

 ==========================================

 Title: [Better tuples] Better tuples

 (In this bug report I talk about something similar to std.typecons.Tuple. A
problem with the "tuple" name: structs have a "tupleof" field, but it returns
something quite different from std.typecons.Tuple. This name clash must be
addressed somehow to avoid confusion of newbie D programmers.)

 Some languages as Python show that good tuples (inhomogeneous sequences of
values of arbitrary types, in D they are statically typed) are very handy, they
help a lot in high-level coding.

 Some syntactic support can make tuple usage natural, easy and widespread in D
programs written by all people, even newbies. But the lack of such syntax can
keep them a library feature used only by few programmers and makes impossible
some very useful tuples usage patterns. From my experience I think that in a
language as D that allows operator overloading built-in tuples are more useful
than built-in associative arrays (the main advantage of built-in associative
arrays are their type literals that enjoy type inference).

 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 ) and maybe the apply(). But other features can't just be added, they need
some syntax and semantic support.

 Some other useful things:
 - 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.
 - Some way to reverse the order of the items of a tuple (generating a tuple of
different type).
 - "in" operator for tuples (as for arrays).
 - More tuple-aware functions in Phobos, like a function to build an AA from a
range of tuple(key, value).
 - 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.

 ------------

 See the enhancement requests: bug 4381 , bug xxxx , bug xxxx , bug xxxx , bug
xxxx , bug xxxx

 (This bug report will have dependencies on other six but reports.)
 (I will append to bug 4381 a reference to this bug.)

 ==========================================

 Title: [Better tuples] Tuple unpacking

 This is one of the tuple enhancement requests. See bug xxxx for an
introduction.

 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):

 auto foo() {
      return tuple(10, "hello");
 }
 void main() {
      (int n, string s) = foo();
      writeln(n, " ", s);
      (n, s) = foo(); // calls is again
      int[] arr = [1, 2, 3];
      (int a, int b, int c) = arr; // other kind of unpacking
      int2[] arr2 = tuple(1, 2, 3);
      (auto n2, auto s2) = foo(); // calls is again
 }

 ------------

 This is the syntax that can be currently used:

 auto foo() {
      T1 alpha = computeIt1(...);
      T1 alpha = computeIt2(...);
      return Tuple!(T1, "alpha", T2, "beta")(alpha, beta);
      //return tuple(alpha, beta); // alternative
 }
 void main() {
      auto alpha_beta = foo();
      use1(alpha_beta.alpha);
      use2(alpha_beta.beta);
      use1(alpha_beta.field[0]); // alternative
      use2(alpha_beta.field[1]);  // alternative
 }

 ------------

 More syntax that can be currently used:

 import std.stdio, std.typecons;
 void main() {
      int[] arr2 = [tuple(1, 2, 3).tupleof];
      writeln(arr2);
 }

 But it prints:
 1 2 3 1 2 3
 Instead of:
 [1, 2, 3]

 ------------

 Optional features, more advanced, that can be added later if they are seen
worth it. They are inspired by Python 2.x and 3.x syntax.

 Nested unpacking:

 auto foo() {
    return tuple(10, tuple("hello", 1.5));
 }
 void main() {
    (int i, (string s, double d)) = foo();
 }



 Python 3.x supports a partial tuple unpacking (here 'rest' will contain the
tuple ("hello", 1.5) ):

 def bar():
    return (10, "hello", 1.5)
 i, *rest = foo()

 But I don't know if this is worth adding to D.

 ==========================================

 Title: [Better tuples] [] syntax support for tuples

 This is one of the tuple enhancement requests. See bug xxxx for an
introduction.

 opIndex/opIndexAssign syntax support for tuples:

 auto tup = tuple(10, 20, 30, 40);
 writeln(tup[0]);
 tup[1] = 5;
 int y = tup[2];
 tup[3]++;


 Slice syntax for tuples (currently done with 'Tuple.slice'):
 auto tup = tuple(10, 20, 30, 40, 50, 60);
 auto part = tup[1 .. 3];


 The type of tuple elements can differ, so the index must be known at
compile-time, just as with tupleof[].

 A possible way to implement it (currently this can't be used):
 alias this.tupleof[0..$] this;

 ==========================================

 Title: [Better tuples] (static) foreach on tuple items

 This is one of the tuple enhancement requests. See bug xxxx for an
introduction.

 auto tup = tuple(10, 20, 30);
 static foreach (item; tup)
      writeln(item);


 See also bug 4085


 Note: in dmd v2.047 this prints all fields twice:

 foreach (item; tup.tupleof)
      writeln(item);

 ==========================================

 Title: [Better tuples] Apply with tuples

 This is one of the tuple enhancement requests. See bug xxxx for an
introduction.

 Apply functionality is quite useful, as shown by this small Python program
that prints "1, 2":

 def foo(x, y):
      print x, y
 tuple1 = (1, 2)
 foo(*tuple1)


 That star syntax of Python is equivalent to this, that works still in Python
2.x:

 def foo(x, y):
      print x, y
 tuple1 = (1, 2)
 apply(foo, tuple1)

 The star syntax can't be used in D, but a good apply() function can be useful
in D too.


 A possible usage in D:

 void foo(T1, T2)(T1 x, T2 y) {
      writeln(x, " ", y);
 }
 void main() {
      auto tuple1 = tuple(1, 2);
      apply(&foo!(tuple1[0].typeof, tuple1[1].typeof), tuple1);
      auto tuple2 = tuple(1, 2, 3);
      apply(&foo!(tuple2[0].typeof, tuple2[1].typeof), tuple2[0..2]);
 }

 ==========================================

 Bye,
 bearophile

I admit that my experience with Tuples is limited, and I haven't put much thought into this suggestion, but would it make sense to make struct instances and tuples the same thing? I wonder if there are any operations that would make sense on one but not the other?
Jun 30 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Eric Poggel:
would it make sense to make struct instances and tuples the same thing?<

It's a nice idea, but if all structs become tuples, and D needs to support separate compilation, then modules that define structs need to contain the compiled methods (instantiated templates) that implement all the features of Tuples. So to keep programs small I think it's better to keep structs simple, and define a Tuple with richer semantics. Bye, bearophile
Jun 30 2010
parent Eric Poggel <dnewsgroup yage3d.net> writes:
On 6/30/2010 8:03 PM, bearophile wrote:
 Eric Poggel:
 would it make sense to make struct instances and tuples the same thing?<

It's a nice idea, but if all structs become tuples, and D needs to support separate compilation, then modules that define structs need to contain the compiled methods (instantiated templates) that implement all the features of Tuples. So to keep programs small I think it's better to keep structs simple, and define a Tuple with richer semantics. Bye, bearophile

That's a shame. I feel like this (along with functions and delgates being different) is one of the areas where the complexity of the language really shows itself. I really liked the proposals you presented though.
Jul 01 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0016e6dd8c7492d617048a59076f
Content-Type: text/plain; charset=ISO-8859-1

On Thu, Jul 1, 2010 at 01:13, bearophile <bearophileHUGS lycos.com> wrote:

 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.

OK, here I go. 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. 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 )

Yes this one (adding a .length member) seems easy. just add either property size_t length() { return Types.length; } or immutable length = Types.length
 and maybe the apply(). But other features can't just be added, they need
 some syntax and semantic support.

 Some other useful things:
 - 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.

I like that, as the range associated to AA is quite naturally a lazy Tuple!(K,V)[]. opSlice() is not defined for AA, so whe not use it to return a range? auto range = aa[]; // lazily produce (K,V) pairs
 - Some way to reverse the order of the items of a tuple (generating a tuple
 of different type).

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. You can these there: http://svn.dsource.org/projects/dranges/trunk/dranges/docs/tuple2.html - "in" operator for tuples (as for arrays).

Yes, and that seems easily implementable. I use this: bool contains(U, T...)(Tuple!T tup, U elem) { static if (staticIndexOf!(U,T) == -1) return false; else { foreach(i, Type; tup.Types) { static if (is(Type == U)) if (tup.field[i] == elem) return true; } return false; } } 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...
 - More tuple-aware functions in Phobos, like a function to build an AA from
 a range of tuple(key, value).

Oh yes.
 - 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.

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.
 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):

 auto foo() {
    return tuple(10, "hello");
 }
 void main() {
    (int n, string s) = foo();

I also woud like that. While waiting to convince Walter, we can use some poor man alternative like this one: void copy(T...)(ref T to, Tuple!T from) { foreach(i,Type; T) { to[i] = from.field[i]; } } usage: auto t = tuple(1, 3.14, "abc"); int i; double d; string s; copy(i,d,s, t); otherwise, you can use this: auto ids = t.expand; ids is an instantiated typetuple: you can index it (ids[1]), slice it (ids[0..2]), iterate on it with foreach, etc. The only thing you cannot do is returning it from a function ... I know it's not as good as what you want (where you define and assign you n and s in one go).
    writeln(n, " ", s);
    (n, s) = foo(); // calls is again
    int[] arr = [1, 2, 3];
    (int a, int b, int c) = arr; // other kind of unpacking

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 _). This gave the following syntax: int n; string s; _(n,s) = foo(); ------------
 This is the syntax that can be currently used:

 auto foo() {
    T1 alpha = computeIt1(...);
    T1 alpha = computeIt2(...);
    return Tuple!(T1, "alpha", T2, "beta")(alpha, beta);
    //return tuple(alpha, beta); // alternative
 }
 void main() {
    auto alpha_beta = foo();
    use1(alpha_beta.alpha);
    use2(alpha_beta.beta);
    use1(alpha_beta.field[0]); // alternative
    use2(alpha_beta.field[1]);  // alternative
 }

You can also use ._x: use1(alpha_beta._0); use1(alpha_beta._1);
 ------------

 More syntax that can be currently used:

 import std.stdio, std.typecons;
 void main() {
    int[] arr2 = [tuple(1, 2, 3).tupleof];
    writeln(arr2);
 }

 But it prints:
 1 2 3 1 2 3
 Instead of:
 [1, 2, 3]

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? (** test, hmm no, doesn't work **) I personnaly use expand a lot: auto t = tuple(1,2,3); int[] arr2 = [t.expand]; // works. I like that to couple tuples and functions: void foo(int i, double d, string s) {} auto t = tuple(1, 3.14, "abc"); foo(t.expand); // works.
 opIndex/opIndexAssign syntax support for tuples:

 auto tup = tuple(10, 20, 30, 40);
 writeln(tup[0]);
 tup[1] = 5;
 int y = tup[2];
 tup[3]++;


 Slice syntax for tuples (currently done with 'Tuple.slice'):
 auto tup = tuple(10, 20, 30, 40, 50, 60);
 auto part = tup[1 .. 3];

Once again, you can use ._x, .field or .expand for that. It's not perfect, but it's not bad either: auto t = tuple(1, 3.14, "abc"); writeln(tup._0); // writes 1 t._1 = 1.414; // t is now tuple(1, 1.414, "abc") string s = t._2; t._0++; // works alternative syntax (.field or .expand) writeln(t.field[0]); t.field[1] = 1.414; string s = t.field[2]; t.field[0]++; And for slicing: 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)) auto t3 = tuple(t.field[1..3]); t3 is a bone fide Tuple!(double, string) Man, typetuples are almost perfect... If only they could once again be returned from functions...
 The type of tuple elements can differ, so the index must be known at
 compile-time, just as with tupleof[].

 A possible way to implement it (currently this can't be used):
 alias this.tupleof[0..$] this;

Tuple code list bug 2800 as a blocker for this.
 ==========================================

 Title: [Better tuples] (static) foreach on tuple items

 This is one of the tuple enhancement requests. See bug xxxx for an
 introduction.

 auto tup = tuple(10, 20, 30);
 static foreach (item; tup)
    writeln(item);

So, you can use: foreach(index, item; tup.expand) writeln(item); (apply => smelting a tuple to give it to a function)
 A possible usage in D:

 void foo(T1, T2)(T1 x, T2 y) {
    writeln(x, " ", y);
 }
 void main() {
    auto tuple1 = tuple(1, 2);
    apply(&foo!(tuple1[0].typeof, tuple1[1].typeof), tuple1);
    auto tuple2 = tuple(1, 2, 3);
    apply(&foo!(tuple2[0].typeof, tuple2[1].typeof), tuple2[0..2]);
 }

OK, at the risk of repeating myself, why not like this? void main() { auto t = tuple(1,"abc"); foo(t.expand); auto t2 = tuple(3.14, 1, "abc"); foo(t2.field[1..$]); } It's not that bad, no? Philippe --0016e6dd8c7492d617048a59076f Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Thu, Jul 1, 2010 at 01:13, bearophile <span d= ir=3D"ltr">&lt;<a href=3D"mailto:bearophileHUGS lycos.com">bearophileHUGS l= ycos.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" style= =3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); p= adding-left: 1ex;"> I&#39;d like to add five enhancement requests in Bugzilla, related to std.t= ypecons.Tuple. I show them here first for possible comments or critiques.<b= r></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 ca= se other people reading this didn&#39;t know them=A0 either.<br> <br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0p= t 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 ver= y important features. Some features can just be added to it (see for exampl= e bug 4381 ) </blockquote><div><br>Yes this one (adding a .length member) s= eems easy. <br> <br>just add either<br><br> property size_t length() { return Types.length;= }<br><br>or<br><br>immutable length =3D Types.length<br><br><br>=A0</div><= blockquote class=3D"gmail_quote" style=3D"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 nee= d some syntax and semantic support.<br> <br> Some other useful things:<br> - More integration and usage of Tuple in druntime. For example the associat= ive array property AA.byItem() can yield tuple(key,value) lazily, and AA.it= ems can return a dynamic array of them.<br></blockquote><div><br>I like tha= t, 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><b= r>auto range =3D aa[]; // lazily produce (K,V) pairs<br><br>=A0</div><block= quote class=3D"gmail_quote" style=3D"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 do= n&#39;t think these should be part of any standard library.<br> <br>You can these there:<br><a href=3D"http://svn.dsource.org/projects/dran= ges/trunk/dranges/docs/tuple2.html">http://svn.dsource.org/projects/dranges= /trunk/dranges/docs/tuple2.html</a><br><br><br></div><blockquote class=3D"g= mail_quote" style=3D"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 conta= ins(U, T...)(Tuple!T tup, U elem)<br>{<br>=A0=A0=A0 static if (staticIndexO= f!(U,T) =3D=3D -1)<br> =A0=A0=A0=A0=A0=A0=A0 return false;<br>=A0=A0=A0 else<br>=A0=A0=A0 {<br>=A0= =A0=A0=A0=A0=A0=A0 foreach(i, Type; tup.Types)<br>=A0=A0=A0=A0=A0=A0=A0 {<b= r>=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 static if (is(Type =3D=3D U))<br>=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (tup.field[i] =3D=3D elem) retur= n true;<br>=A0=A0=A0=A0=A0=A0=A0 }<br>=A0=A0=A0=A0=A0=A0=A0 return false;<b= r> =A0=A0=A0 }<br>}<br><br>But I now see I could iterate directly by jumping a= t staticIndexOf(U,T) and if the value is not OK, continuing on the tail. Th= ough on most cases, tuples have only a few elements...<br><br><br><br>=A0<b= r></div> <blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; borde= r-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>=A0<br><= /div><blockquote class=3D"gmail_quote" style=3D"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 effi= ciency they yield a pair of pointers. But this breaks abstraction. Using a = more common data structure has significant advantages. The compiler can rec= ognize the idiom and in some cases can avoid the creation of the Tuples tha= t 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. It= s 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 str= uct that cannot be fed to other functions.<br> <br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0p= t 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 thi= s syntax can be used in D):<br> <br> auto foo() {<br> =A0 =A0return tuple(10, &quot;hello&quot;);<br> }<br> void main() {<br> =A0 =A0(int n, string s) =3D foo();<br></blockquote><div><br>I also woud l= ike that. While waiting to convince Walter, we can use some poor man altern= ative like this one:<br><br>void copy(T...)(ref T to, Tuple!T from)<br>{<br=

=3D from.field[i];<br>=A0=A0=A0 }<br>}<br><br>usage:<br><br>auto t =3D tupl= e(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 =3D 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 y= ou n and s in one go).<br><br>=A0</div><blockquote class=3D"gmail_quote" st= yle=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204)= ; padding-left: 1ex;"> =A0 =A0writeln(n, &quot; &quot;, s);<br> =A0 =A0(n, s) =3D foo(); // calls is again<br> =A0 =A0int[] arr =3D [1, 2, 3];<br> =A0 =A0(int a, int b, int c) =3D arr; // other kind of unpacking<br></bloc= kquote><div><br>I experimented with a struct called RefTuple, that took con= structor values by ref and that did the kind of destructuring you present h= ere. I created it with a function called _=A0 (yes, just _).<br> This gave the following syntax:<br><br>int n; string s;<br>_(n,s) =3D foo()= ;<br><br><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0= pt 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> =A0 =A0T1 alpha =3D computeIt1(...);<br> =A0 =A0T1 alpha =3D computeIt2(...);<br> =A0 =A0return Tuple!(T1, &quot;alpha&quot;, T2, &quot;beta&quot;)(alpha, b= eta);<br> =A0 =A0//return tuple(alpha, beta); // alternative<br> }<br> void main() {<br> =A0 =A0auto alpha_beta =3D foo();<br> =A0 =A0use1(alpha_beta.alpha);<br> =A0 =A0use2(alpha_beta.beta);<br> =A0 =A0use1(alpha_beta.field[0]); // alternative<br> =A0 =A0use2(alpha_beta.field[1]); =A0// alternative<br> }<br></blockquote><div><br>You can also use ._x:<br><br>use1(alpha_beta._0)= ;<br>use1(alpha_beta._1);<br><br>=A0</div><blockquote class=3D"gmail_quote"= style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 2= 04); padding-left: 1ex;"> <br> ------------<br> <br> More syntax that can be currently used:<br> <br> import std.stdio, std.typecons;<br> void main() {<br> =A0 =A0int[] arr2 =3D [tuple(1, 2, 3).tupleof];<br> =A0 =A0writeln(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 possi= ble 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 =3D tuple(1,2,3);<br>int[] arr= 2 =3D [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= =3D tuple(1, 3.14, &quot;abc&quot;);<br> <br>foo(t.expand); // works.<br>=A0<br></div><blockquote class=3D"gmail_quo= te" style=3D"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 =3D tuple(10, 20, 30, 40);<br> writeln(tup[0]);<br> tup[1] =3D 5;<br> int y =3D tup[2];<br> tup[3]++;<br> <br> <br> Slice syntax for tuples (currently done with &#39;Tuple.slice&#39;):<br> auto tup =3D tuple(10, 20, 30, 40, 50, 60);<br> auto part =3D 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 ba= d either:<br><br>auto t =3D tuple(1, 3.14, &quot;abc&quot;);<br>writeln(tup= ._0); // writes 1<br> t._1 =3D 1.414;=A0=A0=A0=A0=A0=A0 // t is now tuple(1, 1.414, &quot;abc&quo= t;)<br>string s =3D t._2;<br>t._0++; // works<br><br><br>alternative syntax= (.field or .expand)<br><br>writeln(t.field[0]);<br>t.field[1] =3D 1.414;<b= r>string s =3D t.field[2];<br> t.field[0]++;<br><br>And for slicing:<br><br>auto t2 =3D t.field[1..3]; //b= ut t is an instantiated typetuple (ie, an &#39;old way&#39; tuple, a (int,s= tring), not a std.typecons.Tuple!(int,string))<br>auto t3 =3D 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>=A0<br><br><br></div><blockquote class=3D"gma= il_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(20= 4, 204, 204); padding-left: 1ex;"> <br> <br> The type of tuple elements can differ, so the index must be known at compil= e-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>=A0</div><blockquote class=3D"gmail= _quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204,= 204, 204); padding-left: 1ex;"> <br> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D<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 introduc= tion.<br> <br> auto tup =3D tuple(10, 20, 30);<br> static foreach (item; tup)<br> =A0 =A0writeln(item);<br></blockquote><div><br>So, you can use:<br><br>for= each(index, item; tup.expand) <br>=A0=A0=A0 writeln(item);<br><br><br></div=
<blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; bord=

(apply =3D&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> =A0 =A0writeln(x, &quot; &quot;, y);<br> }<br> void main() {<br> =A0 =A0auto tuple1 =3D tuple(1, 2);<br> =A0 =A0apply(&amp;foo!(tuple1[0].typeof, tuple1[1].typeof), tuple1);<br> =A0 =A0auto tuple2 =3D tuple(1, 2, 3);<br> =A0 =A0apply(&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, wh= y not like this?<br><br>void main() {<br>=A0=A0=A0 auto t =3D tuple(1,&quot= ;abc&quot;);<br>=A0=A0=A0 foo(t.expand); <br>=A0=A0=A0 auto t2 =3D tuple(3.= 14, 1, &quot;abc&quot;);<br> =A0=A0=A0 foo(t2.field[1..$]);<br>}<br><br>It&#39;s not that bad, no?<br><b= r><br>Philippe<br><br></div></div> --0016e6dd8c7492d617048a59076f--
Jul 01 2010