www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Getting nice print of struct for debugging

reply Martin Tschierschke <mt smartdolphin.de> writes:
Hello,
I have a little program where I am filling a struct with values 
from an regex match.
Now I want to display the content of the struct for debugging 
purpose.

If struct is named MyStruct

I can print a list of the field names with:

foreach(fieldname;FieldNameTuple!MyStruct){writef("%s 
",fieldname);}
	
If myvar is of type MyStruct how can I make a table like:

fieldname_1: value_1
fieldname_2: value_2
.
.
fieldname_n: value_n

Is there a way to do this with a single expression in D.

Similar to a ruby call myvar.send(fieldname) to get the value 
from fieldname inside a loop?
write(myvar); sure is working directly but I want to get the 
field names displayed, too.

(A work around might be work with the format("%s",myvar) string 
and extract the values with an index?)

Regards mt.
Feb 20
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 20 February 2017 at 16:04:17 UTC, Martin Tschierschke 
wrote:
 Hello,
 I have a little program where I am filling a struct with values 
 from an regex match.
 Now I want to display the content of the struct for debugging 
 purpose.
I believe the easiest way to do this is to define a custom toString member function for your struct. For example: struct MyStruct { int x; double y; string s; string toString() { import std.format: format; return "MyStruct(x: %d, y: %f, s: \"%s\")".format(x, y, s); } } void main() { import std.stdio: writeln; MyStruct foo; foo.x =2; foo.y = 3.14; foo.s = "the quick brown fox"; writeln(foo); // Prints MyStruct(x: 2, y: 3.140000, s: "the quick brown fox") }
Feb 20
parent Martin Tschierschke <mt smartdolphin.de> writes:
On Monday, 20 February 2017 at 16:18:58 UTC, Paul Backus wrote:
 On Monday, 20 February 2017 at 16:04:17 UTC, Martin 
 Tschierschke wrote:
 Hello,
 I have a little program where I am filling a struct with 
 values from an regex match.
 Now I want to display the content of the struct for debugging 
 purpose.
I believe the easiest way to do this is to define a custom toString member function for your struct. For example: struct MyStruct { int x; double y; string s; string toString() { import std.format: format; return "MyStruct(x: %d, y: %f, s: \"%s\")".format(x, y, s); } } void main() { import std.stdio: writeln; MyStruct foo; foo.x =2; foo.y = 3.14; foo.s = "the quick brown fox"; writeln(foo); // Prints MyStruct(x: 2, y: 3.140000, s: "the quick brown fox") }
Good suggestion, thank you! Then the definition is near the struct definition and I do not need to care about what to call, just writeln(myvar); cool!
Feb 20
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-02-20 17:04, Martin Tschierschke wrote:
 Hello,
 I have a little program where I am filling a struct with values from an
 regex match.
 Now I want to display the content of the struct for debugging purpose.

 If struct is named MyStruct

 I can print a list of the field names with:

 foreach(fieldname;FieldNameTuple!MyStruct){writef("%s ",fieldname);}

 If myvar is of type MyStruct how can I make a table like:

 fieldname_1: value_1
 fieldname_2: value_2
 .
 .
 fieldname_n: value_n

 Is there a way to do this with a single expression in D.

 Similar to a ruby call myvar.send(fieldname) to get the value from
 fieldname inside a loop?
 write(myvar); sure is working directly but I want to get the field names
 displayed, too.

 (A work around might be work with the format("%s",myvar) string and
 extract the values with an index?)
Yes, this works, I would say this is the simplest: MyStruct s; foreach (index, name ; FieldNameTuple!MyStruct) writefln("%s: %s", name, s.tupleof[index]); If you want something more close to "send" in Ruby, you need to use a string mixin, like this: foreach (name ; FieldNameTuple!MyStruct) writefln("%s: %s", name, mixin("s." ~ name)); The string mixin example works for methods, opDispatch and similar as well. The tupleof example, the first one, works only for fields. -- /Jacob Carlborg
Feb 21
parent reply Martin Tschierschke <mt smartdolphin.de> writes:
On Tuesday, 21 February 2017 at 14:02:54 UTC, Jacob Carlborg 
wrote:
[...]
 Yes, this works, I would say this is the simplest:

 MyStruct s;

 foreach (index, name ; FieldNameTuple!MyStruct)
     writefln("%s: %s", name, s.tupleof[index]);

 If you want something more close to "send" in Ruby, you need to 
 use a string mixin, like this:

 foreach (name ; FieldNameTuple!MyStruct)
     writefln("%s: %s", name, mixin("s." ~ name));

 The string mixin example works for methods, opDispatch and 
 similar as well. The tupleof example, the first one, works only 
 for fields.
Exactly what I was looking for, **thank you!** Both ways of accessing the struct elements are very interesting, giving an impression what is possible with D. Is it possible to overwrite "toString" for all structs in one step? Regards mt.
Feb 22
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2017-02-22 12:18, Martin Tschierschke wrote:

 Exactly what I was looking for, **thank you!**
 Both ways of accessing the struct elements are very interesting,
 giving an impression what is possible with D.


 Is it possible to overwrite "toString" for all structs in one step?
It depends. You can create a template mixin containing the implementation of toString, which need to be mixed in in all structs. Or you can create a new function that can convert any passed in structs in a generic way. It depends on what you need the string for. -- /Jacob Carlborg
Feb 24
prev sibling parent reply Minty Fresh <minty fresh.com> writes:
On Wednesday, 22 February 2017 at 11:18:15 UTC, Martin 
Tschierschke wrote:
 On Tuesday, 21 February 2017 at 14:02:54 UTC, Jacob Carlborg 
 wrote:
 [...]
 Yes, this works, I would say this is the simplest:

 MyStruct s;

 foreach (index, name ; FieldNameTuple!MyStruct)
     writefln("%s: %s", name, s.tupleof[index]);

 If you want something more close to "send" in Ruby, you need 
 to use a string mixin, like this:

 foreach (name ; FieldNameTuple!MyStruct)
     writefln("%s: %s", name, mixin("s." ~ name));

 The string mixin example works for methods, opDispatch and 
 similar as well. The tupleof example, the first one, works 
 only for fields.
Exactly what I was looking for, **thank you!** Both ways of accessing the struct elements are very interesting, giving an impression what is possible with D. Is it possible to overwrite "toString" for all structs in one step? Regards mt.
Since structs are Plain-old Data and don't do inheritance, the best option is a template mixin. ie. template mixin PrettyPrint { string toString() { // . . . } } From there, you can mix it into any struct you want. struct MyStruct { mixin PrettyPrint; } If you're familiar with Rails, this is similar to a Concern.
Feb 24
parent reply Minty Fresh <minty fresh.com> writes:
On Saturday, 25 February 2017 at 01:27:09 UTC, Minty Fresh wrote:
 On Wednesday, 22 February 2017 at 11:18:15 UTC, Martin 
 Tschierschke wrote:
 [...]
Since structs are Plain-old Data and don't do inheritance, the best option is a template mixin. ie. template mixin PrettyPrint { string toString() { // . . . } } From there, you can mix it into any struct you want. struct MyStruct { mixin PrettyPrint; } If you're familiar with Rails, this is similar to a Concern.
Errata on that. Should actually be declared as: mixin template PrettyPrint() This is why I shouldn't make posts from my phone.
Feb 24
parent Martin Tschierschke <mt smartdolphin.de> writes:
On Saturday, 25 February 2017 at 01:30:09 UTC, Minty Fresh wrote:
 On Saturday, 25 February 2017 at 01:27:09 UTC, Minty Fresh 
 wrote:
 On Wednesday, 22 February 2017 at 11:18:15 UTC, Martin 
 Tschierschke wrote:
 [...]
Since structs are Plain-old Data and don't do inheritance, the best option is a template mixin. ie. template mixin PrettyPrint { string toString() { // . . . } } From there, you can mix it into any struct you want. struct MyStruct { mixin PrettyPrint; } If you're familiar with Rails, this is similar to a Concern.
Errata on that. Should actually be declared as: mixin template PrettyPrint() This is why I shouldn't make posts from my phone.
Thank you, but this solution from Kevin Brogan, is an good alternative, to add a special dump function globally, so no need to modify the struct definitions. https://forum.dlang.org/post/yewavntuyutdvejwjamp forum.dlang.org His solution: import std.traits; void main() { WSADATA wsa; dump!wsa; } void dump(alias variable)() { writeln("\nDumping ",typeid(typeof(variable)),":\n"); writeln(variable.stringof, " = \n{"); foreach(member; FieldNameTuple!(typeof(variable))) { writeln("\t", member, ": ", mixin("variable."~member) ); } writeln("}\n"); }
Feb 27