Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
March 26, 2014 Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Hi, I'd like to generate a toString() method for my classes. For example: --- import std.stdio; class Foo { int x; int y; // mixin ...? } void main() { auto foo = new Foo; foo.x = 1; foo.y = 2; writeln(foo); // prints "Foo(x = 1, y = 2)" } --- I tried using getAllMembers, but that also gives me all methods of Foo. I just want the fields. I also tried FieldTypeTuple (http://dlang.org/phobos/std_traits.html#FieldTypeTuple) but I get that gives me the types. And then I can't find anything else in std.traits that could help me. Is this possible? Thanks, Ary |
March 26, 2014 Re: Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ary Borenszweig | Ary Borenszweig:
> I tried using getAllMembers, but that also gives me all methods of Foo. I just want the fields.
You can try to filter the results of getAllMembers.
Bye,
bearophile
|
March 26, 2014 Re: Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ary Borenszweig | On Wednesday, 26 March 2014 at 14:16:08 UTC, Ary Borenszweig wrote:
> I'd like to generate a toString() method for my classes. For example:
Try this:
override string toString() {
import std.conv;
string s;
s ~= this.classinfo.name ~ "(";
foreach(idx, val; this.tupleof) {
if(idx) s ~= ", ";
s ~= this.tupleof[idx].stringof[5 .. $];
s ~= " = ";
s ~= to!string(val);
}
s ~= ")";
return s;
}
add that method to Foo.
$ ./test58
test58.Foo(x = 1, y = 2)
|
March 26, 2014 Re: Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 3/26/14, 11:47 AM, Adam D. Ruppe wrote:
> On Wednesday, 26 March 2014 at 14:16:08 UTC, Ary Borenszweig wrote:
>> I'd like to generate a toString() method for my classes. For example:
>
> Try this:
>
> override string toString() {
> import std.conv;
> string s;
> s ~= this.classinfo.name ~ "(";
> foreach(idx, val; this.tupleof) {
> if(idx) s ~= ", ";
> s ~= this.tupleof[idx].stringof[5 .. $];
> s ~= " = ";
> s ~= to!string(val);
> }
> s ~= ")";
> return s;
> }
>
> add that method to Foo.
>
> $ ./test58
> test58.Foo(x = 1, y = 2)
Thanks! That's pretty neat. It seems I was missing "tupleof".
|
March 26, 2014 Re: Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ary Borenszweig | On Wednesday, 26 March 2014 at 14:53:55 UTC, Ary Borenszweig wrote:
> Thanks! That's pretty neat. It seems I was missing "tupleof".
Yea, there's other options too like __traits(derivedMembers) if(!is(__traits(getMember...)) == function) and stuff like that, filtering like bearophile said, I just think tupleof is the easiest option for this.
|
March 26, 2014 Re: Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 3/26/14, 11:47 AM, Adam D. Ruppe wrote:
> On Wednesday, 26 March 2014 at 14:16:08 UTC, Ary Borenszweig wrote:
>> I'd like to generate a toString() method for my classes. For example:
>
> Try this:
>
> override string toString() {
> import std.conv;
> string s;
> s ~= this.classinfo.name ~ "(";
> foreach(idx, val; this.tupleof) {
> if(idx) s ~= ", ";
> s ~= this.tupleof[idx].stringof[5 .. $];
> s ~= " = ";
> s ~= to!string(val);
> }
> s ~= ")";
> return s;
> }
>
> add that method to Foo.
>
> $ ./test58
> test58.Foo(x = 1, y = 2)
A small question: tupleof seems to return a tuple of values. So this.tupleof[idx] would return a value. However when you do this.tupleof[idx].stringof that somehow gets the name of the field. Shouldn't it return the name of the value? I'm confused.
|
March 26, 2014 Re: Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ary Borenszweig | that's what i did in a hurry. it seems to work, but the code is very ugly. [/code] import std.conv, std.stdio, std.string, std.traits; string gen_printer (alias cn) () { string res = "override string toString () {\nstring res = `" ~ cn.stringof ~ "(`;\n"; bool need_comma = false; foreach (i, m; __traits(derivedMembers, cn)) { static if (!isCallable!(__traits(getMember, cn, m)) /*&& m != "Monitor"*/) { if (need_comma) res ~= `res ~= ", ";`; else need_comma = true; res ~= "res~=`" ~ m ~ " = `~to!string(" ~ m ~ ");"; } } res ~= "res~=`)`;\n"; res ~= "return res;\n}\n"; return res; } class Foo { int x; int y; void test () {} mixin(gen_printer!Foo); } void main () { auto foo = new Foo; foo.x = 1; foo.y = 2; writefln("%s", foo); // prints "Foo(x = 1, y = 2)" } [/code] |
March 26, 2014 Re: Generate toString() method at compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ary Borenszweig | On Wednesday, 26 March 2014 at 15:01:35 UTC, Ary Borenszweig wrote:
> A small question: tupleof seems to return a tuple of values.
Most accurately, it returns a tuple of variables (it is a bit magical). So
struct A { int a; string b; }
the tupleof there is int a; string b - variables with different types and different names. The stringof works as if you said A.a.stringof - it fetches the name of the variable.
The slice I did on it cuts off the "this." from the full name, leaving just the name.
Value to string is done with the to!string function, .stringof always works at compile time.
|
Copyright © 1999-2021 by the D Language Foundation