View mode: basic / threaded / horizontal-split · Log in · Help
November 21, 2011
mixin on identifier
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
November 21, 2011
Re: mixin on identifier
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;
> }
November 22, 2011
Re: mixin on identifier
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;
>> }
>
November 22, 2011
Re: mixin on identifier
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;
>>> }
>>
>
November 22, 2011
Re: mixin on identifier
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;
>>>> }
>>>
>>
>
November 22, 2011
Re: mixin on identifier
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
November 30, 2011
Re: mixin on identifier
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.
November 30, 2011
Re: mixin on identifier
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
Top | Discussion index | About this forum | D home