www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - alias tuples?

reply "Janice Caron" <caron800 googlemail.com> writes:
We've got value tuples, and we've got type tuples. Could we also have
alias tuples?

Here's what I mean. Right now I can do:

struct A
{
    X x;
    Y y;
    Z z;

    mixin Serialize!(x,y,z);
}
A a;

template Serialize(alias x,alias y,alias z)
{
    void serialize()
    {
        x.serialize();
        y.serialize();
        z.serialize();
    }
}

where the types X, Y and Z all have a serialize() function (and so on
recursively for every object in need of serialization). Now it seems
to me, if I wanted to make Serialize!() variadic, I'd need not a value
tuple, nor a type tuple, but an "alias tuple". I'd want to be able to
write something like:

struct A
{
    X x;
    Y y;
    Z z;

    mixin Serialize!(this.aliastupleof); /* expands to (x,y,z) */
}
A a;

template Serialize(alias T...)
{
    void serialize()
    {
        foreach(a;T)
            a.serialize();
    }
}

Of course this won't work right now. The template won't compile
because (alias T...) has no meaning, and even if it did, structs don't
have an aliastupleof property.

Thoughts?
Oct 13 2007
next sibling parent Reiner Pope <some address.com> writes:
Janice Caron wrote:
 We've got value tuples, and we've got type tuples. Could we also have
 alias tuples?
 
 Here's what I mean. Right now I can do:
 
 struct A
 {
     X x;
     Y y;
     Z z;
 
     mixin Serialize!(x,y,z);
 }
 A a;
 
 template Serialize(alias x,alias y,alias z)
 {
     void serialize()
     {
         x.serialize();
         y.serialize();
         z.serialize();
     }
 }
 
 where the types X, Y and Z all have a serialize() function (and so on
 recursively for every object in need of serialization). Now it seems
 to me, if I wanted to make Serialize!() variadic, I'd need not a value
 tuple, nor a type tuple, but an "alias tuple". I'd want to be able to
 write something like:
 
 struct A
 {
     X x;
     Y y;
     Z z;
 
     mixin Serialize!(this.aliastupleof); /* expands to (x,y,z) */
 }
 A a;
 
 template Serialize(alias T...)
 {
     void serialize()
     {
         foreach(a;T)
             a.serialize();
     }
 }
 
 Of course this won't work right now. The template won't compile
 because (alias T...) has no meaning, and even if it did, structs don't
 have an aliastupleof property.
 
 Thoughts?

You can sort of fake it. You could write your first example as struct A { int x = 1; int y = 2; int z = 3; void serialize() { .serialize(this.tupleof); // or .serialize(x, z); if you want } } void serialize(T...)(T t) { foreach (t2; t) typeSpecificSerialize(t2); // or t2.serialize(), but that won't work with int } void typeSpecificSerialize(T)(T t) { writefln("%s: %s", T.stringof, t); // or whatever you want } --- But you don't get the variable names this way. If you want that, you can do the following, although you lose the variadic bit: void serialize(T)(T t) { foreach (i, t2; t.tupleof) { writefln("%s: [%s]", T.tupleof[i].stringof, t2); } } struct foo { int a = 1; int b = 2; } void main() { foo f; serialize(f); } --- I hope that helps, although it's not what you asked for. ;) -- Reiner
Oct 14 2007
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message 
news:mailman.422.1192341718.16939.digitalmars-d puremagic.com...
 We've got value tuples, and we've got type tuples. Could we also have
 alias tuples?

 Here's what I mean. Right now I can do:

 struct A
 {
    X x;
    Y y;
    Z z;

    mixin Serialize!(x,y,z);
 }
 A a;

 template Serialize(alias x,alias y,alias z)
 {
    void serialize()
    {
        x.serialize();
        y.serialize();
        z.serialize();
    }
 }

 where the types X, Y and Z all have a serialize() function (and so on
 recursively for every object in need of serialization). Now it seems
 to me, if I wanted to make Serialize!() variadic, I'd need not a value
 tuple, nor a type tuple, but an "alias tuple". I'd want to be able to
 write something like:

 struct A
 {
    X x;
    Y y;
    Z z;

    mixin Serialize!(this.aliastupleof); /* expands to (x,y,z) */
 }
 A a;

 template Serialize(alias T...)
 {
    void serialize()
    {
        foreach(a;T)
            a.serialize();
    }
 }

 Of course this won't work right now. The template won't compile
 because (alias T...) has no meaning, and even if it did, structs don't
 have an aliastupleof property.

 Thoughts?

In fact you can do this all without tuples, at least as parameters to templates. class X { void serialize() {} } class Y : X{} class Z : X{} struct A { X x; Y y; Z z; mixin Serialize; } template Serialize() { void serialize() { foreach(a; this.tupleof) a.serialize(); } }
Oct 14 2007
parent reply =?ISO-8859-1?Q?Manuel_K=F6nig?= <ManuelK89 gmx.net> writes:
Janice Caron wrote:
 I'm a little confused at how that works.
 
 Surely, this.tupleof returns a type tuple - that is, a sequence of
 types? Surely then, the "a" in the foreach would be a type, not a
 member variable name? Surely then, a.serialize() would be calling each
 type's /static/ serialize() function, rather than the member function?
 
 The goal is to call a function once for each actual struct member, not
 once for each member's type.
 
 Am I completely misunderstanding this?

looking at http://www.digitalmars.com/d/tuple.html it says: "The data fields of a struct or class can be turned into an _expression_ tuple using the .tupleof property" (below that you find an example that actually uses it) I tested it myself and it works. I actually use it to implement functions in a generic matrix struct. But http://www.digitalmars.com/d/tuple.html (section Struct Properties) states: ".tupleof Gets _type_ tuple of fields" I think that's a typo and should be fixed.
Oct 14 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Manuel König" <ManuelK89 gmx.net> wrote in message 
news:feu01n$cs1$1 digitalmars.com...
 Janice Caron wrote:

 ".tupleof Gets _type_ tuple of fields"

 I think that's a typo and should be fixed.

I think it's just a bit unclear/inconsistent. For a struct S, S.tupleof gets a tuple of its members' types. But S s; s.tupleof gets a tuple of the instance s's members. Same goes for classes. And unions.
Oct 14 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
I'm a little confused at how that works.

Surely, this.tupleof returns a type tuple - that is, a sequence of
types? Surely then, the "a" in the foreach would be a type, not a
member variable name? Surely then, a.serialize() would be calling each
type's /static/ serialize() function, rather than the member function?

The goal is to call a function once for each actual struct member, not
once for each member's type.

Am I completely misunderstanding this?
Oct 14 2007
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/14/07, Manuel König <ManuelK89 gmx.net> wrote:
 looking at http://www.digitalmars.com/d/tuple.html it says:

 "The data fields of a struct or class can be turned into an _expression_
 tuple using the .tupleof  property"
 (below that you find an example that actually uses it)

 I tested it myself and it works.

You mean this...? # struct S { int x; long y; } # # void foo(int a, long b) # { # writefln(a, b); # } # # ... # S s; # s.x = 7; # s.y = 8; # foo(s.x, s.y); // prints 78 # foo(s.tupleof); // prints 78 # s.tupleof[1] = 9; # s.tupleof[0] = 10; # foo(s.tupleof); // prints 109 # s.tupleof[2] = 11; // error, no third field of S OK, that's slightly more interesting. It looks like S.tupleof gets you type tuple, while s.tupleof gets you an expression tuple. But neither is what I'm looking for. I want to get _aliases_ into a tuple. This would open the door to powerful variadic metaprogramming, just as (non-variadic) alias template parameters do for (non-variadic) templates. Going back to structs, for example, member variable names are features of S (the structure declaration), not of s (an instance of S), so if we wanted to automate their extraction, you'd need a new property for struct types. But that would only really be icing on the cake, because really it's the aliasing side of things where it would matter most. See, right now, I have a quite nice piece of code which looks a little bit like this (I've simplified it for illustration purposes) struct A { B b; C c; mixin SomeNiceFunctions!(b,c); } struct B { D d; E e; F f; mixin SomeNiceFunctions!(d,e,f); } struct C { F f; G g; D d; H h; mixin SomeNiceFunctions!(f,g,d,h); } Now this is all very cool and marvellous, and already /way/ better than C++, but nonetheless I still have to write several different versions of the mixin, one for each different number of parameters. Specifically: template SomeNiceFunctions!(alias a,alias b) { /*...*/ } template SomeNiceFunctions!(alias a,alias b,alias c) { /*...*/ } template SomeNiceFunctions!(alias a,alias b,alias c,alias d) { /*...*/ } How much nicer it would be to instead be able to do: template SomeNiceFunctions!(alias a...) { /*...*/ } and then use a foreach (static foreach?) within the definition to dereference each alias in turn. That's really what I'm getting at. (Being able to automate the parameter list at the mixin site would be a nice added bonus, but not essential).
Oct 14 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message 
news:mailman.442.1192397473.16939.digitalmars-d puremagic.com...

 OK, that's slightly more interesting. It looks like S.tupleof gets you
 type tuple, while s.tupleof gets you an expression tuple. But neither
 is what I'm looking for. I want to get _aliases_ into a tuple. This
 would open the door to powerful variadic metaprogramming, just as
 (non-variadic) alias template parameters do for (non-variadic)
 templates.

 Going back to structs, for example, member variable names are features
 of S (the structure declaration), not of s (an instance of S), so if
 we wanted to automate their extraction, you'd need a new property for
 struct types. But that would only really be icing on the cake, because
 really it's the aliasing side of things where it would matter most.

 See, right now, I have a quite nice piece of code which looks a little
 bit like this (I've simplified it for illustration purposes)

 struct A
 {
    B b;
    C c;

    mixin SomeNiceFunctions!(b,c);
 }

 struct B
 {
    D d;
    E e;
    F f;

    mixin SomeNiceFunctions!(d,e,f);
 }

 struct C
 {
    F f;
    G g;
    D d;
    H h;

    mixin SomeNiceFunctions!(f,g,d,h);
 }

 Now this is all very cool and marvellous, and already /way/ better
 than C++, but nonetheless I still have to write several different
 versions of the mixin, one for each different number of parameters.
 Specifically:

 template SomeNiceFunctions!(alias a,alias b) { /*...*/ }
 template SomeNiceFunctions!(alias a,alias b,alias c) { /*...*/ }
 template SomeNiceFunctions!(alias a,alias b,alias c,alias d) { /*...*/ }

 How much nicer it would be to instead be able to do:

 template SomeNiceFunctions!(alias a...) { /*...*/ }

 and then use a foreach (static foreach?) within the definition to
 dereference each alias in turn. That's really what I'm getting at.

 (Being able to automate the parameter list at the mixin site would be
 a nice added bonus, but not essential).

Maybe you didn't know this, but tuple parameters can be any mix of types, expressions, and aliases. This is already entirely possible. class X { void serialize() {} }; class Y : X{} class Z : X{} struct A { X x; Y y; Z z; mixin SomeNiceFunctions!(x, y, z); } template SomeNiceFunctions(T...) { static if(T.length > 0) { mixin(typeof(T[0]).stringof ~ " get" ~ T[0].stringof ~ "() { return " ~ T[0].stringof ~ "; }"); static if(T.length > 1) mixin SomeNiceFunctions!(T[1 .. $]); } } void main() { A a; Stdout.formatln("{}", a.getx() is null); }
Oct 14 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message 
news:feumc4$1qi7>>
 (Being able to automate the parameter list at the mixin site would be
 a nice added bonus, but not essential).


To comment further on this point, it _may_ be possible with D 1.0 but I can't manage to mangle the code enough to get the compiler to accept it. I think this would be much easier with D 2.0's compile-time reflection capabilities.
Oct 14 2007