Better tuples

Eric Poggel dnewsgroup at yage3d.net
Wed Jun 30 16:33:50 PDT 2010


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?


More information about the Digitalmars-d mailing list