www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - mixin on identifier

reply Johannes Totz <johannes jo-t.de> writes:
Hi!

I'm trying to do:

mixin template StateOne()
{
	int	value;
}

class StateSet(T)
{
	mixin T;
}

int main(string[] argv)
{
	StateSet!StateOne	s = new StateSet!StateOne();

	return 0;
}

Compiler complains with:
main.d(18): Error: template instance StateSet!(StateOne) 
StateSet!(StateOne) does not match template declaration StateSet(T)
main.d(18): Error: StateSet!(StateOne) is used as a type

I think I understand why. And from what I figured I'd need string 
mixins? But I can't figure out how...
Any hints?



Johannes
Nov 21 2011
parent reply David Nadlinger <see klickverbot.at> writes:
Make T an alias parameter:
class StateSet(alias T) { … }

David


On 11/22/11 12:38 AM, Johannes Totz wrote:
 mixin template StateOne()
 {
      int    value;
 }

 class StateSet(T)
 {
      mixin T;
 }

 int main(string[] argv)
 {
      StateSet!StateOne    s = new StateSet!StateOne();

      return 0;
 }
Nov 21 2011
parent reply Johannes Totz <johannes jo-t.de> writes:
On 21/11/2011 23:39, David Nadlinger wrote:
 Make T an alias parameter:
 class StateSet(alias T) { … }

 David
Thanks! I was trying to get to something like this: mixin template StateOne() { int value; } mixin template StateTwo() { float data; } class StateSet(alias T ...) { mixin T; } int main(string[] argv) { StateSet!(StateOne, StateTwo) s = new StateSet!(StateOne, StateTwo)(); return 0; } With the docs I got to: template StateSet(alias T, S ...) { class StateSet { mixin T; } } But I have no clue how to expand S into mixin statements.
 On 11/22/11 12:38 AM, Johannes Totz wrote:
 mixin template StateOne()
 {
 int value;
 }

 class StateSet(T)
 {
 mixin T;
 }

 int main(string[] argv)
 {
 StateSet!StateOne s = new StateSet!StateOne();

 return 0;
 }
Nov 21 2011
parent reply David Nadlinger <see klickverbot.at> writes:
Turns out to be surprisingly tricky… A possible solution is:

mixin template StateOne() {
   int value;
}

mixin template StateTwo() {
   float data;
}

mixin template MixinAll(T...) {
   static if (T.length > 0) {
     alias T[0] A;
     mixin A;
     mixin MixinAll!(T[1 .. $]);
   }
}

class StateSet(T...){
   mixin MixinAll!T;
}

void main() {
   auto s = new StateSet!(StateOne, StateTwo)();
}

Hope this helps,
David


On 11/22/11 1:02 AM, Johannes Totz wrote:
 On 21/11/2011 23:39, David Nadlinger wrote:
 Make T an alias parameter:
 class StateSet(alias T) { … }

 David
Thanks! I was trying to get to something like this: mixin template StateOne() { int value; } mixin template StateTwo() { float data; } class StateSet(alias T ...) { mixin T; } int main(string[] argv) { StateSet!(StateOne, StateTwo) s = new StateSet!(StateOne, StateTwo)(); return 0; } With the docs I got to: template StateSet(alias T, S ...) { class StateSet { mixin T; } } But I have no clue how to expand S into mixin statements.
 On 11/22/11 12:38 AM, Johannes Totz wrote:
 mixin template StateOne()
 {
 int value;
 }

 class StateSet(T)
 {
 mixin T;
 }

 int main(string[] argv)
 {
 StateSet!StateOne s = new StateSet!StateOne();

 return 0;
 }
Nov 21 2011
parent reply Johannes Totz <johannes jo-t.de> writes:
On 22/11/2011 04:57, David Nadlinger wrote:
 Turns out to be surprisingly tricky… A possible solution is:

 mixin template StateOne() {
 int value;
 }

 mixin template StateTwo() {
 float data;
 }

 mixin template MixinAll(T...) {
 static if (T.length > 0) {
 alias T[0] A;
 mixin A;
 mixin MixinAll!(T[1 .. $]);
 }
 }

 class StateSet(T...){
 mixin MixinAll!T;
 }

 void main() {
 auto s = new StateSet!(StateOne, StateTwo)();
 }

 Hope this helps,
 David
Thanks a lot, David! A new variant of this (notice the func()s): mixin template StateOne() { int value; void func(int d) { value = d; } } mixin template StateTwo() { float data; void func(float d) { data = d; } } mixin template MixinAll(T...) { static if (T.length > 0) { alias T[0] A; mixin A; mixin MixinAll!(T[1 .. $]); } } class StateSet(T...) { mixin MixinAll!T; } int main(string[] argv) { auto s = new StateSet!(StateOne, StateTwo)(); s.value = 1; s.data = 3.1f; s.func(2); // Error s.func(4.5f); // Ok return 0; } Error: main.StateSet!(StateOne,StateTwo).StateSet.MixinAll!(StateOne,StateTwo).MixinAll! StateTwo).A!().func at main.d(20) conflicts with main.StateSet!(StateOne,StateTwo).StateSet.MixinAll!(StateOne StateTwo).A!().func at main.d(10) I suppose I get the error at the first func() call because int is implicitly convertible to float. Is it really? Also, I tried to make the mixed-in members private/etc but this does not seem to have any effect...
 On 11/22/11 1:02 AM, Johannes Totz wrote:
 On 21/11/2011 23:39, David Nadlinger wrote:
 Make T an alias parameter:
 class StateSet(alias T) { … }

 David
Thanks! I was trying to get to something like this: mixin template StateOne() { int value; } mixin template StateTwo() { float data; } class StateSet(alias T ...) { mixin T; } int main(string[] argv) { StateSet!(StateOne, StateTwo) s = new StateSet!(StateOne, StateTwo)(); return 0; } With the docs I got to: template StateSet(alias T, S ...) { class StateSet { mixin T; } } But I have no clue how to expand S into mixin statements.
 On 11/22/11 12:38 AM, Johannes Totz wrote:
 mixin template StateOne()
 {
 int value;
 }

 class StateSet(T)
 {
 mixin T;
 }

 int main(string[] argv)
 {
 StateSet!StateOne s = new StateSet!StateOne();

 return 0;
 }
Nov 22 2011
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Hi there,

template recursion can get difficult to write sometimes. For the mixin
part, since what you're doing is looping on States, another solution
is to use string mixins:

string stateCode(States...)()
{
    string code;
    foreach(state; States)
        code ~= "mixin " ~ __traits(identifier, state) ~ ";\n";
    return code;
}

class StateSet(States...)
{
    mixin(stateCode!(States));
}

void main()
{
    auto s = new StateSet!(StateOne, StateTwo)();
    s.func(1.5);
}

the 'stateCode' function produces the code you want inside StateSet
and is then mixed in (by a string mixin, not a template mixin).
At least to my eyes, the global effect is easier to follow and as a
bonus you have access to the entire language to manipulate the
strings: slicing, library functions, etc. Hey, now that CT regex are a
reality, pretty nifty code manipulation could be done, I guess.


Halas, that doesn't change your int/float problem. In the above code,
s.func(1) doesn't compile.

Strangely, manually inserting the code *does* work:

class StateSet(States...) // I don't care for States
{
    int i;
    void func(int i) { writeln("int: ", i);}
    float f;
    void func(float f) { writeln("float: ", f);}
}

void main()
{
    auto s = new StateSet!(StateOne, StateTwo)(); // or whatever
    s.func(1);
    s.func(1.0);
}

So, maybe it's a compiler bug or mixin templates do not work as I
thought they worked. Because, to me, the resulting code inside
StateSet should be the same.

Workaround: string mixins again:

string StateOne() // Note that it's now a function
{
    return q{
        int i;
        void func(int i) { writeln("int: ", i);}
   };
}

string StateTwo()
{
    return q{
        float f;
        void func(float f) { writeln("float: ", f);}
   };
}

string stateCode(States...)()
{
    string code;
    foreach(state; States) code ~= state ~ ";\n";
    return code;
}

class StateSet(States...) // States will here store function names
{
    mixin( stateCode!States );
}

void main()
{
    auto s = new StateSet!(StateOne, StateTwo)();
    s.func(1);
    s.func(1.0);
}

On the plus side: it works.
Disadvantage: you're manipulating strings, so the code 'inside' the
strings is not checked...

But I get the feeling that tuples should get you what you want. Could
you expand a bit more on the usage you envision for StateSet?


Philippe
Nov 22 2011
next sibling parent Johannes Totz <johannes jo-t.de> writes:
On 22/11/2011 21:11, Philippe Sigaud wrote:
 Hi there,

 template recursion can get difficult to write sometimes. For the mixin
 part, since what you're doing is looping on States, another solution
 is to use string mixins:

 string stateCode(States...)()
 {
      string code;
      foreach(state; States)
          code ~= "mixin " ~ __traits(identifier, state) ~ ";\n";
      return code;
 }

 class StateSet(States...)
 {
      mixin(stateCode!(States));
 }

 void main()
 {
      auto s = new StateSet!(StateOne, StateTwo)();
      s.func(1.5);
 }

 the 'stateCode' function produces the code you want inside StateSet
 and is then mixed in (by a string mixin, not a template mixin).
 At least to my eyes, the global effect is easier to follow and as a
 bonus you have access to the entire language to manipulate the
 strings: slicing, library functions, etc. Hey, now that CT regex are a
 reality, pretty nifty code manipulation could be done, I guess.


 Halas, that doesn't change your int/float problem. In the above code,
 s.func(1) doesn't compile.

 Strangely, manually inserting the code *does* work:

 class StateSet(States...) // I don't care for States
 {
      int i;
      void func(int i) { writeln("int: ", i);}
      float f;
      void func(float f) { writeln("float: ", f);}
 }

 void main()
 {
      auto s = new StateSet!(StateOne, StateTwo)(); // or whatever
      s.func(1);
      s.func(1.0);
 }

 So, maybe it's a compiler bug or mixin templates do not work as I
 thought they worked. Because, to me, the resulting code inside
 StateSet should be the same.

 Workaround: string mixins again:

 string StateOne() // Note that it's now a function
 {
      return q{
          int i;
          void func(int i) { writeln("int: ", i);}
     };
 }

 string StateTwo()
 {
      return q{
          float f;
          void func(float f) { writeln("float: ", f);}
     };
 }

 string stateCode(States...)()
 {
      string code;
      foreach(state; States) code ~= state ~ ";\n";
      return code;
 }

 class StateSet(States...) // States will here store function names
 {
      mixin( stateCode!States );
 }

 void main()
 {
      auto s = new StateSet!(StateOne, StateTwo)();
      s.func(1);
      s.func(1.0);
 }
Thanks!
 On the plus side: it works.
 Disadvantage: you're manipulating strings, so the code 'inside' the
 strings is not checked...

 But I get the feeling that tuples should get you what you want. Could
 you expand a bit more on the usage you envision for StateSet?
It's a toy project for me to learn D. I'm trying to recreate something I wrote in C++ once. It used extremely messy MPL to have a class inherit individual states from template parameters. But the problem was that func() would not overload from inherited classes. So I tought D's mixins might be suitable.
Nov 30 2011
prev sibling parent Johannes Totz <johannes jo-t.de> writes:
On 22/11/2011 21:11, Philippe Sigaud wrote:
 Hi there,

 template recursion can get difficult to write sometimes. For the mixin
 part, since what you're doing is looping on States, another solution
 is to use string mixins:

 string stateCode(States...)()
 {
      string code;
      foreach(state; States)
          code ~= "mixin " ~ __traits(identifier, state) ~ ";\n";
      return code;
 }

 class StateSet(States...)
 {
      mixin(stateCode!(States));
 }

 void main()
 {
      auto s = new StateSet!(StateOne, StateTwo)();
      s.func(1.5);
 }

 the 'stateCode' function produces the code you want inside StateSet
 and is then mixed in (by a string mixin, not a template mixin).
 At least to my eyes, the global effect is easier to follow and as a
 bonus you have access to the entire language to manipulate the
 strings: slicing, library functions, etc. Hey, now that CT regex are a
 reality, pretty nifty code manipulation could be done, I guess.


 Halas, that doesn't change your int/float problem. In the above code,
 s.func(1) doesn't compile.

 Strangely, manually inserting the code *does* work:

 class StateSet(States...) // I don't care for States
 {
      int i;
      void func(int i) { writeln("int: ", i);}
      float f;
      void func(float f) { writeln("float: ", f);}
 }

 void main()
 {
      auto s = new StateSet!(StateOne, StateTwo)(); // or whatever
      s.func(1);
      s.func(1.0);
 }

 So, maybe it's a compiler bug or mixin templates do not work as I
 thought they worked. Because, to me, the resulting code inside
 StateSet should be the same.
Maybe this bug is related: http://d.puremagic.com/issues/show_bug.cgi?id=1182 Looks like the functions are not supposed to overload, would need an explicit alias.
 Workaround: string mixins again:

 string StateOne() // Note that it's now a function
 {
      return q{
          int i;
          void func(int i) { writeln("int: ", i);}
     };
 }

 string StateTwo()
 {
      return q{
          float f;
          void func(float f) { writeln("float: ", f);}
     };
 }

 string stateCode(States...)()
 {
      string code;
      foreach(state; States) code ~= state ~ ";\n";
      return code;
 }

 class StateSet(States...) // States will here store function names
 {
      mixin( stateCode!States );
 }

 void main()
 {
      auto s = new StateSet!(StateOne, StateTwo)();
      s.func(1);
      s.func(1.0);
 }

 On the plus side: it works.
 Disadvantage: you're manipulating strings, so the code 'inside' the
 strings is not checked...

 But I get the feeling that tuples should get you what you want. Could
 you expand a bit more on the usage you envision for StateSet?


 Philippe
Nov 30 2011