www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 9593] New: Optional type-free printing of a std.typecons.Tuple

http://d.puremagic.com/issues/show_bug.cgi?id=9593

           Summary: Optional type-free printing of a std.typecons.Tuple
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: Phobos
        AssignedTo: nobody puremagic.com
        ReportedBy: bearophile_hugs eml.cc



Recently the format string of writefln has gained an optional "-" that doesn't
print the "" of strings, and it's useful in several situations:


import std.stdio: writeln, writefln;
void main() {
    auto data = ["Fred", "Bob", "Mark"];
    writefln("%s", data);
    writeln();
    writefln("%-(%s %)", data);
}


Output (dmd 2.063alpha):

["Fred", "Bob", "Mark"]

Fred Bob Mark

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

If you have to print an array of tuples:


import std.stdio: writeln;
import std.typecons: Tuple;
alias Counter = Tuple!(string,"name", size_t,"count");
void main() {
    auto data = [Counter("Fred", 5), Counter("Bob", 10), Counter("Mark", 30)];
    writeln(data);
    writeln();
    immutable data2 = [Counter("Fred", 5), Counter("Bob", 10), Counter("Mark",
30)];
    writeln(data2);
}



The output:

[Tuple!(string, "name", uint, "count")("Fred", 5), Tuple!(string, "name", uint,
"count")("Bob", 10), Tuple!(string, "name", uint, "count")("Mark", 30)]

[immutable(Tuple!(string, "name", uint, "count"))("Fred", 5),
immutable(Tuple!(string, "name", uint, "count"))("Bob", 10),
immutable(Tuple!(string, "name", uint, "count"))("Mark", 30)]

As you notice when you have to print arrays of tuples the output is noisy.
Writeln doesn't know that Tuple is named "Counter", so it gives the types and
field names for all the tuples (despite it's an array, so all of its items are
of the same type...).

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

This is a bigger example that shows why printing the full type of tuples
sometimes is not handy:


import std.typecons: Tuple, tuple;
import std.string: format;
import std.array: replace;

abstract class Tree {
    override string toString() const;
}

final class Conclusion : Tree {
    string result;

    static typeof(this) opCall(typeof(result) result_) {
        auto r = new typeof(this)();
        r.result = result_;
        return r;
    }

    override string toString() const {
        return `Conclusion("` ~ result ~ `")`;
    }
}

final class Choice : Tree {
    string key;
    Tuple!(string, Tree)[] branches;

    static typeof(this) opCall(typeof(key) key_,
                               typeof(branches) branches_) {
        auto r = new typeof(this)();
        r.key = key_;
        r.branches = branches_;
        return r;
    }

    override string toString() const {
        return format(`Choice("%s", %s)`, key, branches);
    }
}

void main() {
    import std.stdio;
    alias B = typeof(Choice.branches[0]);

    auto t = Choice("Sci-Fi",
                    [B("No", Choice("Action",
                                    [B("Yes", Conclusion("Stallone")),
                                     B("No", Conclusion("Schwarzenegger"))])),
                     B("Yes", Conclusion("Schwarzenegger"))]);

    writeln(t);
}



It prints:

Choice("Sci-Fi", [const(Tuple!(string, Tree))("No", Choice("Action",
[const(Tuple!(string, Tree))("Yes", Conclusion("Stallone")),
const(Tuple!(string, Tree))("No", Conclusion("Schwarzenegger"))])),
const(Tuple!(string, Tree))("Yes", Conclusion("Schwarzenegger"))])


For me that's hard to read.

To produce a bit better output I have to strip away the types and field names:

    override string toString() const {
        return format(`Choice("%s", %s)`, key, branches)
               .replace("const(Tuple!(string, Tree))", "B");
    }


So the printing becomes acceptable:

Choice("Sci-Fi", [("No", Choice("Action", [("Yes", Conclusion("Stallone")),
("No", Conclusion("Schwarzenegger"))])), ("Yes",
Conclusion("Schwarzenegger"))])


This is useful for debugging, for short script-like programs, during the
development of code, etc.

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

Python has a "namedtuple", it has a less noisy and better printing because it's
designed to know its name (and Python is dynamically typed, so generally types
are not printed, unless you ask for them, as in the last two lines of this REPL
session):


 from collections import namedtuple
 Counter = namedtuple("Counter", "name count")
 data = [Counter("Fred", 5), Counter("Bob", 10), Counter("Mark", 30)]
 print data
[Counter(name='Fred', count=5), Counter(name='Bob', count=10), Counter(name='Mark', count=30)]
 print type(data[0].name)
<type 'str'> - - - - - - - - - - - - - - - - - - - - - - - - - - - There are various ways to solve the problem of the noisy printing of the array of D Tuples. An idea is to print only the full type of the first tuple of an array, but this is a bad idea: [Tuple!(string, "name", uint, "count")("Fred", 5), ("Bob", 10), ("Mark", 30)] This is a little better but not good enough still: <Tuple!(string, "name", uint, "count")[]>[("Fred", 5), ("Bob", 10), ("Mark", 30)] - - - - - - - - - - - - - - - - - - - - - - - - - - - A better solution is to introduce a new format that disables the printing of the tuple type (see also Issue 9592 ): writeln(data[0]); ==> Tuple!(string, "name", uint, "count")("Fred", 5) writefln("%-s", data[0]); ==> ("Fred", 5) writefln("%-(%s %)", data); ==> ("Fred", 5) ("Bob", 10) ("Mark", 30) - - - - - - - - - - - - - - - - - - - - - - - - - - - -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Feb 25 2013