www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Phobos Members-Tuple function?

reply "F i L" <witte2008 gmail.com> writes:
Is there a function in phobos which will return a Tuple of a 
Type's members, for use in a foreach statement?

I need this for collecting info on all Type Members's User 
Attributes. Currently, I have written a recursive function which 
does this, but I'm looking for a more elegant solution.

Let's say I have an Ship Actor class:

     class Ship : Actor
     {
          Bind("Stage.update") void update()
         {
             // ...
         }

          Bind("Canvas.draw") void draw()
         {
             // ...
         }
     }

and I want to iterator over all it's members.. and, in turn, 
iterate over all their attributes. If I use 
"__traits(derivedMembers, Ship)" it returns a Tuple of strings, 
which I can't use with __traits(getAttributes, ..). So what are 
my options here? Ideally, I'd like to be able to do this:

     auto ship = new Ship;
     enum mbrs = membersOf(Ship); // returns Tuple
     foreach (m; mbrs)
     {
         enum atrs = __traits(getAttributes, m);
         foreach (a; atrs)
         {
             if (is(a : Bind))
                 Engine.bindActors(ship, a.pattern);
         }
     }

Like I said, I've already accomplished this using recursion. I'm 
just wondering if there's an easier way (like above). Also, if 
recursive functions are required, I'd love to hear ideas on the 
best way to write a general purpose recursive function for this 
kind of thing.
Jan 19 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
F i L:

 I need this for collecting info on all Type Members's User 
 Attributes. Currently, I have written a recursive function 
 which does this, but I'm looking for a more elegant solution.
I have not fully understood the problem, but have you tried [__traits(getAttributes, m)] ? Bye, bearophile
Jan 19 2013
parent "F i L" <witte2008 gmail.com> writes:
bearophile wrote:
 I have not fully understood the problem, but have you tried 
 [__traits(getAttributes, m)] ?
yes, that's not really relevant to my problem. 'm' in your example, can't be read at compile time, because __traits(derivedMembers, ..) returns a Tuple of strings, not Symbols. I can get the attributes of a specific member just fine, the problem is iterating over *all* members, then finding the attributes for each member. It's relatively easy to solve with recursion, I'm just trying to cover my tracks here and see if there's a better way I'm unaware of.
Jan 19 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/19/2013 12:10 PM, F i L wrote:
 Is there a function in phobos which will return a Tuple of a Type's
 members, for use in a foreach statement?
The following program produces this output: member update attribute Bind("Stage.update") Binding actor with pattern Stage.update member draw attribute Bind("Canvas.draw") Binding actor with pattern Canvas.draw member toString member toHash member opCmp member opEquals member Monitor member factory I had to use a mixin and had to move __traits(allMembers) into the foreach loop. It was necessary so that 'm' could be evaluated at compile time. I can kind of see why but one would expect your 'enum mbrs' to work as well. import std.stdio; interface Actor {} struct Bind { string pattern; } class Ship : Actor { Bind("Stage.update") void update() { // ... } Bind("Canvas.draw") void draw() { // ... } } class Engine { static bindActors(Actor, string pattern) { writefln(" Binding actor with pattern %s", pattern); } } void main() { auto ship = new Ship; alias T = typeof(ship); foreach (m; __traits(allMembers, T)) { writefln("member %s", m); enum atrs = __traits(getAttributes, mixin(T.stringof ~ "." ~ m)); foreach (a; atrs) { writefln(" attribute %s", a); if (is(typeof(a) == Bind)) Engine.bindActors(ship, a.pattern); } } } Ali
Jan 19 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/19/2013 06:41 PM, Ali Çehreli wrote:

 class Engine
 {
 static bindActors(Actor, string pattern)
 {
 writefln(" Binding actor with pattern %s", pattern);
 }
 }
How come that function compiles without a return type? The following is a bug, right? class C { static foo() // <-- no return type; void is assumed {} } void main() { static assert(is(typeof(C.foo()) == void)); } Ali
Jan 19 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/20/2013 03:59 AM, Ali Çehreli wrote:
 On 01/19/2013 06:41 PM, Ali Çehreli wrote:

  > class Engine
  > {
  > static bindActors(Actor, string pattern)
  >     {
  >         writefln(" Binding actor with pattern %s", pattern);
  >     }
  > }

 How come that function compiles without a return type? The following is
 a bug, right?

 class C
 {
      static foo()  // <-- no return type; void is assumed
      {}
 }

 void main()
 {
      static assert(is(typeof(C.foo()) == void));
 }

 Ali
Not a bug. This is function return type deduction. If you return something from foo, then the return type will change. What is often missed is that 'auto' does not mean anything. It exists just to make the parser happy.
Jan 19 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/20/2013 03:41 AM, Ali Çehreli wrote:
 ...
 void main()
 {
      auto ship = new Ship;
      alias T = typeof(ship);

      foreach (m; __traits(allMembers, T))
      {
          writefln("member %s", m);

          enum atrs = __traits(getAttributes, mixin(T.stringof ~ "." ~ m));
This only works because Ship happens to be defined in the same module. Use __traits(getMember, T, m) instead of the mixin.
          foreach (a; atrs)
          {
              writefln("  attribute %s", a);
              if (is(typeof(a) == Bind))
                  Engine.bindActors(ship, a.pattern);
          }
      }
 }

 Ali
Jan 19 2013
prev sibling parent reply "F i L" <witte2008 gmail.com> writes:
Ali Çehreli wrote:
 The following program produces this output:

 [...code...]
Awesome! Thanks, I wasn't expecting it to actually be as easy as that. I tried all sort of difference combinations with __traits(allMembers, ..) but it looks like I just needed to move it into the foreach loop itself. I wounder why there's a difference when assigning to an enum...
Jan 19 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/20/2013 04:55 AM, F i L wrote:
 Ali Çehreli wrote:
 The following program produces this output:

 [...code...]
Awesome! Thanks, I wasn't expecting it to actually be as easy as that. I tried all sort of difference combinations with __traits(allMembers, ..) but it looks like I just needed to move it into the foreach loop itself. I wounder why there's a difference when assigning to an enum...
foreach over an enum constant is not magically unrolled statically like foreach over a sequence ("TypeTuple") is. (The somewhat related fact that static foreach over a sequence of enum values does not work is a compiler bug.)
Jan 19 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/20/2013 06:59 AM, Timon Gehr wrote:
 The somewhat related fact that static foreach over a sequence of enum
 values does not work is a compiler bug.
I guess this is your problem. (The original post was confusing because it contained pseudo code.) To prevent confusion in the future, please always post the full code snippet.
Jan 19 2013