Bug 9593 – Optional type-free printing of a std.typecons.Tuple

Status
NEW
Severity
enhancement
Priority
P4
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-02-25T19:00:59Z
Last change time
2024-12-01T16:16:36Z
Assigned to
No Owner
Creator
bearophile_hugs
See also
https://issues.dlang.org/show_bug.cgi?id=3248
Moved to GitHub: phobos#9954 →

Comments

Comment #0 by bearophile_hugs — 2013-02-25T19:00:59Z
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) - - - - - - - - - - - - - - - - - - - - - - - - - - -
Comment #1 by andrej.mitrovich — 2014-05-13T12:48:46Z
*** Issue 12743 has been marked as a duplicate of this issue. ***
Comment #2 by bearophile_hugs — 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))]
Comment #3 by robert.schadek — 2024-12-01T16:16:36Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/phobos/issues/9954 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB