www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Class Data Members Name Reflection

reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
Is there a way to iterate over the symbolic names of the data 
members of a class instance?

I'm currently using .tupleof to get its values (and in turn 
types) to implement   pretty printing to multiple backends 
(currently testing HTML) using as much of D's compile time 
reflection as possible:

https://github.com/nordlow/justd/blob/master/pprint.d

I've currently defined mappings from InputRanges of Aggregates 
(tuples, structs, and classes) to HTML tables where

- the aggregate members are mapped to table columns (and their 
types in turn two column headers) and
- range elements to rows

and I would like to perfect the output by also propagating the 
member names to the column headings.

I'm aware of __traits(allMembers, Type) but those return more 
than .tupleof does.

Help please.
Jun 10 2014
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
Two options: do allMembers and filter it out to only be data 
members, or do some slicing of tupleof.stringof:

S s;
foreach(idx, member; s.tupleof) {
    writeln("Name: ", s.tupleof[idx].stringof[2..$]);
}


The tupleof[idx] inside the loop is important instead of just 
using member because then you get the name, then the slicing is 
because you get:

s.foo

for example, and you want to slice off the "s." to leave just the 
name.
Jun 10 2014
next sibling parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Tuesday, 10 June 2014 at 16:13:31 UTC, Adam D. Ruppe wrote:
 Two options: do allMembers and filter it out to only be data 
 members, or do some slicing of tupleof.stringof:
What trait should I use to filter out data members?
 S s;
 foreach(idx, member; s.tupleof) {
    writeln("Name: ", s.tupleof[idx].stringof[2..$]);
 }
Ok. I tried foreach (ix, memb; arg.args[0].front.tupleof) { import std.stdio: writeln; writeln(arg.args[0].front.tupleof[ix].stringof); } Almost there...except that the print seems to verbose and bit funny: ref FKind __tup4778 = front(arg._args_field_0); , __tup4778.kindName ref FKind __tup4779 = front(arg._args_field_0); , __tup4779.description ref FKind __tup4780 = front(arg._args_field_0); , __tup4780.wikiURL ref FKind __tup4781 = front(arg._args_field_0); Did I do something wrong?
Jun 10 2014
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 10 June 2014 at 16:30:52 UTC, Nordlöw wrote:
 What trait should I use to filter out data members?
No trait, more like an is thing to see if the thing has an init. I think static if(is(typeof(__traits(getMember, Thing, name).init)) { } will do it. (BTW the sample chapter of my book talks about reflection, I think I talked about some of this in there: http://www.packtpub.com/discover-advantages-of-programming-in-d-cookbook/book )
 foreach (ix, memb; arg.args[0].front.tupleof)
Eeek, I actually used s for a reason there - it gives you a simple name that is easily repeated and filtered. The nasty string you're seeing is the name of a compiler-generated temporary variable in the foreach. That said, your field names are in there at the end, so another option would be to run it through lastIndexOf(".") and then slice to that. So it works backward to the dot and slices off the rest of the string. string s = arg.args[0].front.tupleof[idx].stringof; auto dotIndex = s.lastIndexOf("."); assert(dotIndex >= 0); // it ought to be there anyway auto name = s[dotIndex + 1 .. $]; // slice off the temp name, whatever it is
Jun 10 2014
prev sibling parent "Kapps" <opantm2+spam gmail.com> writes:
On Tuesday, 10 June 2014 at 16:13:31 UTC, Adam D. Ruppe wrote:
 Two options: do allMembers and filter it out to only be data 
 members, or do some slicing of tupleof.stringof:

 S s;
 foreach(idx, member; s.tupleof) {
    writeln("Name: ", s.tupleof[idx].stringof[2..$]);
 }


 The tupleof[idx] inside the loop is important instead of just 
 using member because then you get the name, then the slicing is 
 because you get:

 s.foo

 for example, and you want to slice off the "s." to leave just 
 the name.
You may not want to use stringof for this, because stringof is explicitly defined as being able to change across versions, and no actual format is defined. Instead use __traits(identifier, s.tupleof[idx]). Also note that .tupleof will not return static fields.
Jun 10 2014
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Tuesday, 10 June 2014 at 16:10:09 UTC, Nordlöw wrote:
 Is there a way to iterate over the symbolic names of the data 
 members of a class instance?

 I'm currently using .tupleof to get its values (and in turn 
 types) to implement   pretty printing to multiple backends 
 (currently testing HTML) using as much of D's compile time 
 reflection as possible:

 https://github.com/nordlow/justd/blob/master/pprint.d

 I've currently defined mappings from InputRanges of Aggregates 
 (tuples, structs, and classes) to HTML tables where

 - the aggregate members are mapped to table columns (and their 
 types in turn two column headers) and
 - range elements to rows

 and I would like to perfect the output by also propagating the 
 member names to the column headings.

 I'm aware of __traits(allMembers, Type) but those return more 
 than .tupleof does.

 Help please.
I am not sure I understand the question. Does this help? struct A { int x; double y; } void main() { foreach (idx, elem; A.init.tupleof) { pragma(msg, __traits(identifier, A.tupleof[idx])); } } // output: // x // y
Jun 10 2014
next sibling parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
 I am not sure I understand the question. Does this help?

 struct A
 {
 	int x;
 	double y;
 }

 void main()
 {
 	foreach (idx, elem; A.init.tupleof)
 	{
 		pragma(msg, __traits(identifier, A.tupleof[idx]));
 	}
 }

 // output:
 // x
 // y
Exactly what I wanted! BTW: Can DMD serve use file and line location of user defined type aswell? Thx!
Jun 10 2014
parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
 BTW: Can DMD serve use file and line location of user defined 
 type aswell?

 Thx!
Correction: I mean serve *us*
Jun 10 2014
prev sibling parent reply =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Tuesday, 10 June 2014 at 17:29:35 UTC, Dicebot wrote:
 On Tuesday, 10 June 2014 at 16:10:09 UTC, Nordlöw wrote:
 Is there a way to iterate over the symbolic names of the data 
 members of a class instance?

 I'm currently using .tupleof to get its values (and in turn 
 types) to implement   pretty printing to multiple backends 
 (currently testing HTML) using as much of D's compile time 
 reflection as possible:

 https://github.com/nordlow/justd/blob/master/pprint.d

 I've currently defined mappings from InputRanges of Aggregates 
 (tuples, structs, and classes) to HTML tables where

 - the aggregate members are mapped to table columns (and their 
 types in turn two column headers) and
 - range elements to rows

 and I would like to perfect the output by also propagating the 
 member names to the column headings.

 I'm aware of __traits(allMembers, Type) but those return more 
 than .tupleof does.

 Help please.
I am not sure I understand the question. Does this help? struct A { int x; double y; } void main() { foreach (idx, elem; A.init.tupleof) { pragma(msg, __traits(identifier, A.tupleof[idx])); } } // output: // x // y
Notice that A.init.tupleof segfaults for classes so that is _not_ an adviced solution in a generic solution! But fortunately I always have an instance, say a, of A available in the pprint functions so I just use a.tupleof instead! Now it works! I'll update pprint.d later today! I'll further extract away the dumb dependencies for pprint.d in the upcoming days so it can be reused later on. Thanks you all!
Jun 10 2014
parent "Kapps" <opantm2+spam gmail.com> writes:
On Tuesday, 10 June 2014 at 20:01:37 UTC, Nordlöw wrote:
 Notice that A.init.tupleof segfaults for classes so that is 
 _not_ an adviced solution in a generic solution!
There's no need to use .init: import std.stdio; struct Foo { int a, b; } void main() { writeln(__traits(identifier, Foo.tupleof[0])); }
Jun 10 2014