Thread overview
Class Data Members Name Reflection
Jun 10, 2014
Nordlöw
Jun 10, 2014
Adam D. Ruppe
Jun 10, 2014
Nordlöw
Jun 10, 2014
Adam D. Ruppe
Jun 11, 2014
Kapps
Jun 10, 2014
Dicebot
Jun 10, 2014
Nordlöw
Jun 10, 2014
Nordlöw
Jun 10, 2014
Nordlöw
Jun 11, 2014
Kapps
June 10, 2014
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.
June 10, 2014
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.
June 10, 2014
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?
June 10, 2014
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

June 10, 2014
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
June 10, 2014
> 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!
June 10, 2014
> BTW: Can DMD serve use file and line location of user defined type aswell?
>
> Thx!

Correction: I mean serve *us*
June 10, 2014
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!
June 11, 2014
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.
June 11, 2014
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]));
}