Bug 9872 – format should include class field values

Status
NEW
Severity
enhancement
Priority
P4
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-04-04T00:27:25Z
Last change time
2024-12-01T16:17:15Z
Keywords
patch
Assigned to
No Owner
Creator
Andrej Mitrovic
See also
https://issues.dlang.org/show_bug.cgi?id=3248
Moved to GitHub: phobos#9603 →

Comments

Comment #0 by andrej.mitrovich — 2013-04-04T00:27:25Z
This is an unfortunate inconsistency: import std.stdio; import std.string; struct S { int x, y; } class C { int x, y; } void main() { auto s1 = format("%s", S()); auto s2 = format("%s", new C()); writeln(s1); // S(0, 0) writeln(s2); // test.C } It forces us to either always define a toString() method or call some custom user-provided formatting function. format() should try to print the values of the class fields if the toString method is not defined.
Comment #1 by andrej.mitrovich — 2013-04-04T00:32:34Z
Workaround: private mixin template genToString() { override string toString() { import std.array; import std.conv; import std.string; Appender!(string[]) result; foreach (val; this.tupleof) { result ~= to!string(val); } return format("%s(%s)", __traits(identifier, typeof(this)), result.data.join(", ")); } } class C { int x, y; mixin genToString; }
Comment #2 by andrej.mitrovich — 2013-04-04T11:49:19Z
How's this for a funky workaround: diff --git a/std/format.d b/std/format.d index 8896e38..84169c0 100644 --- a/std/format.d +++ b/std/format.d @@ -2512,15 +2512,32 @@ if (is(T == class) && !is(T == enum)) put(w, "null"); else { + Object o = val; // workaround + string delegate() dg = &o.toString; + static if (hasToString!(T, Char) > 1 || (!isInputRange!T && !is(BuiltinTypeOf!T))) { - formatObject!(Writer, T, Char)(w, val, f); + if (dg.funcptr != &Object.toString) + formatObject!(Writer, T, Char)(w, val, f); + else + { + enum ident = __traits(identifier, T); + + mixin(format(q{ + static struct %s + { + typeof(T.tupleof) fields; + } + %s s; + s.fields = val.tupleof; + }, ident, ident)); + + formatValue(w, s, f); + } } else { //string delegate() dg = &val.toString; - Object o = val; // workaround - string delegate() dg = &o.toString; if (dg.funcptr != &Object.toString) // toString is overridden { formatObject(w, val, f); Yeah it's just a joke. But it works. :P
Comment #3 by lt.infiltrator — 2015-12-02T17:18:01Z
I like it. Have you put in a PR yet?
Comment #4 by dlang-bugzilla — 2017-07-07T16:43:58Z
(In reply to Andrej Mitrovic from comment #2) > + if (dg.funcptr != &Object.toString) Pretty devious. I think it's not unreasonable.
Comment #5 by andrej.mitrovich — 2022-07-04T17:09:03Z
I think the really consistent part about formatting in Phobos is that the output tends to be semantically-correct syntax. S(0, 0) is correct as you can construct an instance of `S` this way. But `C(0, 0)` would be semantically incorrect as that's not how classes are constructed. You'd (likely) need to use `new C` and you'd have to care about which constructors are actually implemented, so `new C(0, 0)` might not even be semantically correct either. Perhaps instead of changing default formatting a better option would be to have a format spec that dumps out the entire representation of the aggregate. "%s" is taken but we could introduce something else. We could also just close this as WONTFIX.
Comment #6 by robert.schadek — 2024-12-01T16:17:15Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/phobos/issues/9603 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB