I think std.typecons.Tuples merit to be a little more citizens in D and Phobos.
I think reducing the usage of "out" argument, and replacing them with a tuple 
result, will avoid mistakes and make the code look better. In std.math there 
are functions that maybe are better to use std.typecons.Tuple:

pure nothrow @trusted real frexp(real value, out int exp);
==>
pure nothrow @trusted Tuple!(real, int) frexp(real value);


nothrow @trusted real remquo(real x, real y, out int n); 
==>
nothrow @trusted Tuple!(real, int) remquo(real x, real y); 

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

It's good for tuples to become more common in D code. Some time ago I have 
asked the built-in associative arrays to grow a method to iterate on key-value 
pairs, named "byPair":
http://d.puremagic.com/issues/show_bug.cgi?id=5466

Andrei answered:
>byPair is tricky because std.tuple is not visible from object.

How do you solve this problem?


Now I think about a "pairs" method too:

int[string] aa;
Tuple!(string, int) ps = aa.pairs;
foreach (p; aa.byPair)
        assert(is( typeof(p) == Tuple!(string, int) ));



This example shows an use case of byItem. Given a string, the task here is to 
show the char frequencies, putting higher frequencies on top, and sorting 
alphabetically the chars that share the same frequency.

A Python 2.6 program that solves the problem:


from collections import defaultdict
text = "the d programming language is an object oriented " + \
       "imperative multi paradigm system programming " + \
       "language created by walter bright of digital mars"
frequences = defaultdict(int)
for c in text:
    frequences[c] += 1
pairs = sorted(frequences.iteritems(), key=lambda (c,f): (-f,c))
for (c, f) in pairs:
    print f, c



The output of the Python program:

20  
14 a
12 e
11 g
11 i
11 r
10 t
9 m
6 n
5 d
5 l
5 o
4 p
4 s
3 b
3 u
2 c
2 h
2 y
1 f
1 j
1 v
1 w



Three different solutions in D (probably there are other solutions, maybe even 
better ones) using Phobos:


import std.stdio, std.typecons, std.algorithm, std.array;

void main() {
    auto text = "the d programming language is an object oriented " ~
                "imperative multi paradigm system programming " ~
                "language created by walter bright of digital mars";

    int[char] frequences;
    foreach (char c; text)
        frequences[c]++;

    Tuple!(int,char)[] pairs1 = array(map!(c => tuple(frequences[c], 
c))(frequences.byKey));
    schwartzSort!(p => tuple(-p[0], p[1]))(pairs1);
    foreach (pair; pairs1)
        writeln(pair[0], " ", pair[1]);
    writeln();

    import std.conv;
    dchar[] keys = to!(dchar[])(frequences.keys);
    schwartzSort!(c => tuple(-frequences[cast(char)c], c))(keys);
    foreach (dchar c; keys)
        writeln(frequences[cast(char)c], " ", c);
    writeln();

    Tuple!(int,char)[] pairs1b = array(map!(c => tuple(-frequences[c], 
c))(frequences.byKey));
    sort(pairs1b);
    foreach (pair; pairs1b)
        writeln(-pair[0], " ", pair[1]);
    writeln();
}



A version using AA.pairs (or array(AA.byPair)), I have not used 'auto' for type 
clarity:

Tuple!(char,int)[] pairs2 = frequences.pairs;
schwartzSort!(c_f => tuple(-c_f[1], c_f[0]))(pairs2);
foreach (c_f; pairs2)
    writeln(c_f[1], " ", c_f[0]);



I am now writing a good amount of D2 code, some of it is functional style, or 
it's just translated from Python, and one annoying thing that comes out quite 
frequently is the lack of syntax to unpack a tuple into some variables.

If you want a short self-contained example, this is a small program (and it's 
not much functional. Tuples aren't just for functional-style code):
http://rosettacode.org/wiki/Sokoban#D

It contains code like:

immutable dirs = [tuple( 0, -1, 'u', 'U'),
                  tuple( 1,  0, 'r', 'R'),
                  tuple( 0,  1, 'd', 'D'),
                  tuple(-1,  0, 'l', 'L')];
// ...
foreach (di; dirs) {
    CTable temp = cur;
    immutable int dx = di[0];
    immutable int dy = di[1];


With tuple unpacking becomes:

foreach (di; dirs) {
    CTable temp = cur;
    immutable (dx, dy) = di.slice!(0, 2);


I don't know if this is going to work, because di[0..2] creates a 2-typetuple!

foreach (di; dirs) {
    CTable temp = cur;
    immutable (dx, dy) = di[0 .. 2];


Maybe this is not efficient:

foreach (di; dirs) {
    CTable temp = cur;
    immutable (dx, dy, _1, _2) = di;


Another example from that little program:


alias Tuple!(CTable, string, int, int) Four;
GrowableCircularQueue!Four open;
// ...
while (open.length) {
    immutable item = open.pop();
    immutable CTable cur = item[0];
    immutable string cSol = item[1];
    immutable int x = item[2];
    immutable int y = item[3];


With a tuple unpacking syntax becomes:

while (open.length) {
    immutable (cur, cSol, x, y) = open.pop();


While I use tuples I hit similar situations often.

For people interested in trying this idea, there is a patch by Kenji Hara (one 
or two parts are missing, like tuple unpacking in a foreach(...) and in 
function signatures, but I think most meat is already present):
https://github.com/D-Programming-Language/dmd/pull/341

Bye,
bearophile

Reply via email to