Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional type-free printing of a std.typecons.Tuple #9954

Open
dlangBugzillaToGithub opened this issue Feb 25, 2013 · 2 comments
Open

Optional type-free printing of a std.typecons.Tuple #9954

dlangBugzillaToGithub opened this issue Feb 25, 2013 · 2 comments

Comments

@dlangBugzillaToGithub
Copy link

bearophile_hugs reported this on 2013-02-25T19:00:59Z

Transfered from https://issues.dlang.org/show_bug.cgi?id=9593

Description

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)

- - - - - - - - - - - - - - - - - - - - - - - - - - -
@dlangBugzillaToGithub
Copy link
Author

andrej.mitrovich (@AndrejMitrovic) commented on 2014-05-13T12:48:46Z

*** Issue 12743 has been marked as a duplicate of this issue. ***

@dlangBugzillaToGithub
Copy link
Author

bearophile_hugs commented on 2015-01-08T14:12:18Z

Sometimes the output is so much noisy that it's unreadable:

void main() {
    import std.stdio: writeln;
    import std.algorithm: cartesianProduct;
    import std.range: enumerate;
    auto a = [10, 20];
    cartesianProduct(a.enumerate, a.enumerate)
    .writeln;
}


Output:

[Tuple!(Tuple!(uint, "index", int, "value"), Tuple!(uint, "index", int, "value"))(Tuple!(uint, "index", int, "value")(0, 10), Tuple!(uint, "index", int, "value")(0, 10)), Tuple!(Tuple!(uint, "index", int, "value"), Tuple!(uint, "index", int, "value"))(Tuple!(uint, "index", int, "value")(0, 10), Tuple!(uint, "index", int, "value")(1, 20)), Tuple!(Tuple!(uint, "index", int, "value"), Tuple!(uint, "index", int, "value"))(Tuple!(uint, "index", int, "value")(1, 20), Tuple!(uint, "index", int, "value")(0, 10)), Tuple!(Tuple!(uint, "index", int, "value"), Tuple!(uint, "index", int, "value"))(Tuple!(uint, "index", int, "value")(1, 20), Tuple!(uint, "index", int, "value")(1, 20))]


A similar Python program:

from itertools import product
a = [10, 20]
print list(product(enumerate(a), enumerate(a)))


Prints a readable output:

[((0, 10), (0, 10)), ((0, 10), (1, 20)), ((1, 20), (0, 10)), ((1, 20), (1, 20))]

@LightBender LightBender removed the P4 label Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants