Better tuples

bearophile bearophileHUGS at lycos.com
Wed Jun 30 16:13:52 PDT 2010


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


More information about the Digitalmars-d mailing list