Thread overview
Phobos Members-Tuple function?
Jan 19, 2013
F i L
Jan 19, 2013
bearophile
Jan 19, 2013
F i L
Jan 20, 2013
Ali Çehreli
Jan 20, 2013
Ali Çehreli
Jan 20, 2013
Timon Gehr
Jan 20, 2013
Timon Gehr
Jan 20, 2013
F i L
Jan 20, 2013
Timon Gehr
Jan 20, 2013
Timon Gehr
January 19, 2013
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.
January 19, 2013
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
January 19, 2013
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.
January 20, 2013
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

January 20, 2013
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

January 20, 2013
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.
January 20, 2013
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
>

January 20, 2013
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...
January 20, 2013
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.)
January 20, 2013
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.