| 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
Permalink
Reply