Thread overview
mixin on identifier
Nov 21, 2011
Johannes Totz
Nov 21, 2011
David Nadlinger
Nov 22, 2011
Johannes Totz
Nov 22, 2011
David Nadlinger
Nov 22, 2011
Johannes Totz
Nov 22, 2011
Philippe Sigaud
Nov 30, 2011
Johannes Totz
Nov 30, 2011
Johannes Totz
November 21, 2011
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
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
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
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
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
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
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
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