www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Bug in mixins?

reply "Frustrated" <Frustrated nowhere.com> writes:
I have a mixin template that I use to make programming to 
interfaces easier. The problem is when I try to wrap the template 
to reduce dependence on the container class(using typeof(this)) I 
get an error as the string mixin is not working.

The code can be seen here

http://dpaste.dzfl.pl/6c90ca418996

The lines are 77-81 and 162-163 that are the problems. 
AbstractToInterface(a mixin template) simply wraps 
AbstractToInterface2(a string mixin)

(I haven't removed the container class dependency since it 
doesn't change anything yet but that is the goal)


I have a simplified test case that does work(and does remove the 
extra parameter but, again, that isn't where the problem is).

http://dpaste.dzfl.pl/dd8d1888da44

B is a string mixin template that depends on the container 
class(parameter T). I do not want to have to duplicate that 
argument though since it is not necessary. Hence where the mixin 
template C comes into play. It is able to get the container class 
type and pass it to B.

There is no real difference between the two yet the first gives 
strange errors(I get different errors about assignment(lines 200 
and 212) but dpaste gives more direct results(the properties to 
handle the general case are simply not mixed in).


There should be no difference between the two code examples. They 
both essentially do the same thing(wrap a string mixin). Why one 
works and the other doesn't is beyond me.... seems like a bug 
unless I'm doing something really stupid.

Any ideas?

P.S. The specific error I get is "Error: gui.border is not an 
lvalue" which suggests that the setter properties are not being 
inserted.
Mar 06 2014
next sibling parent "Frustrated" <Frustrated nowhere.com> writes:
Can someone check this out? The best I can acertain is that the 
mixin template isn't adding the generated functions because it 
thinks they are already in the class.

i.e., the code generates the following methods

 property iButton button(iButton b)
 property iBorder border(iBorder b)

and the class contains the methods

 property WindowsButton button()
 property WindowsButton button(WindowsButton b)

and the template mixin simply doesn't add the generic methods. 
(simply because mixing the string mixin directly works, wrapping 
it in a mixin template does not)

Using that I created a MWE:

http://dpaste.dzfl.pl/6f64e49aba95



import std.stdio, std.cstream;

// mixin template used to wrap the string mixin
mixin template C() { mixin(B); }

// eponymously named template used as a string mixin to generate 
the function
template B()
{
	string B() { return "void foo(iA a) { writeln(`Generic`);  }"; }
}

interface iA {	void foo(iA a); }

class A : iA
{
	void foo(A a) { writeln("Specific"); }
	//mixin(B);
	mixin C;    // doesn't work, use line above, does not insert 
generic foo
}


void main()
{
	iA a = new A;
	a.foo(a);
	(cast(A)a).foo(cast(A)a);
	(cast(A)a).foo(a);  // line doesn't work when using mixin 
template because the generic foo does not exist
}


This seems like a bug to me but maybe that's how mixin templates 
work? If so is there any way to make them insert the code 
regardless if it thinks they are the same? (they are not in this 
case and I need to use them to reduce redundancy)
Mar 06 2014
prev sibling next sibling parent "Paul Freund" <freund.paul lvl3.org> writes:
On Friday, 7 March 2014 at 06:23:58 UTC, Frustrated wrote:
 Can someone check this out? The best I can acertain is that the 
 mixin template isn't adding the generated functions because it 
 thinks they are already in the class.

 i.e., the code generates the following methods

  property iButton button(iButton b)
  property iBorder border(iBorder b)

 and the class contains the methods

  property WindowsButton button()
  property WindowsButton button(WindowsButton b)

 and the template mixin simply doesn't add the generic methods. 
 (simply because mixing the string mixin directly works, 
 wrapping it in a mixin template does not)

 Using that I created a MWE:

 http://dpaste.dzfl.pl/6f64e49aba95



 import std.stdio, std.cstream;

 // mixin template used to wrap the string mixin
 mixin template C() { mixin(B); }

 // eponymously named template used as a string mixin to 
 generate the function
 template B()
 {
 	string B() { return "void foo(iA a) { writeln(`Generic`);  }"; 
 }
 }

 interface iA {	void foo(iA a); }

 class A : iA
 {
 	void foo(A a) { writeln("Specific"); }
 	//mixin(B);
 	mixin C;    // doesn't work, use line above, does not insert 
 generic foo
 }


 void main()
 {
 	iA a = new A;
 	a.foo(a);
 	(cast(A)a).foo(cast(A)a);
 	(cast(A)a).foo(a);  // line doesn't work when using mixin 
 template because the generic foo does not exist
 }


 This seems like a bug to me but maybe that's how mixin 
 templates work? If so is there any way to make them insert the 
 code regardless if it thinks they are the same? (they are not 
 in this case and I need to use them to reduce redundancy)

I admit I didn't read the entire description but maybe it is related to this https://d.puremagic.com/issues/show_bug.cgi?id=11954
Mar 07 2014
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 7 March 2014 at 06:23:58 UTC, Frustrated wrote:
 Can someone check this out? The best I can acertain is that the 
 mixin template isn't adding the generated functions because it 
 thinks they are already in the class.

 i.e., the code generates the following methods

  property iButton button(iButton b)
  property iBorder border(iBorder b)

 and the class contains the methods

  property WindowsButton button()
  property WindowsButton button(WindowsButton b)

 and the template mixin simply doesn't add the generic methods. 
 (simply because mixing the string mixin directly works, 
 wrapping it in a mixin template does not)

 Using that I created a MWE:

 http://dpaste.dzfl.pl/6f64e49aba95



 import std.stdio, std.cstream;

 // mixin template used to wrap the string mixin
 mixin template C() { mixin(B); }

 // eponymously named template used as a string mixin to 
 generate the function
 template B()
 {
 	string B() { return "void foo(iA a) { writeln(`Generic`);  }"; 
 }
 }

 interface iA {	void foo(iA a); }

 class A : iA
 {
 	void foo(A a) { writeln("Specific"); }
 	//mixin(B);
 	mixin C;    // doesn't work, use line above, does not insert 
 generic foo
 }


 void main()
 {
 	iA a = new A;
 	a.foo(a);
 	(cast(A)a).foo(cast(A)a);
 	(cast(A)a).foo(a);  // line doesn't work when using mixin 
 template because the generic foo does not exist
 }


 This seems like a bug to me but maybe that's how mixin 
 templates work? If so is there any way to make them insert the 
 code regardless if it thinks they are the same? (they are not 
 in this case and I need to use them to reduce redundancy)

functions introduced through mixin templates do not take part in overload resolution when an overload exists outside the mixin. It's a common annoyance, I can't remember if there's a good reason for it.
Mar 07 2014
prev sibling next sibling parent "Frustrated" <Frustrated nowhere.com> writes:
On Friday, 7 March 2014 at 09:10:45 UTC, John Colvin wrote:
 On Friday, 7 March 2014 at 06:23:58 UTC, Frustrated wrote:
 Can someone check this out? The best I can acertain is that 
 the mixin template isn't adding the generated functions 
 because it thinks they are already in the class.

 i.e., the code generates the following methods

  property iButton button(iButton b)
  property iBorder border(iBorder b)

 and the class contains the methods

  property WindowsButton button()
  property WindowsButton button(WindowsButton b)

 and the template mixin simply doesn't add the generic methods. 
 (simply because mixing the string mixin directly works, 
 wrapping it in a mixin template does not)

 Using that I created a MWE:

 http://dpaste.dzfl.pl/6f64e49aba95



 import std.stdio, std.cstream;

 // mixin template used to wrap the string mixin
 mixin template C() { mixin(B); }

 // eponymously named template used as a string mixin to 
 generate the function
 template B()
 {
 	string B() { return "void foo(iA a) { writeln(`Generic`);  
 }"; }
 }

 interface iA {	void foo(iA a); }

 class A : iA
 {
 	void foo(A a) { writeln("Specific"); }
 	//mixin(B);
 	mixin C;    // doesn't work, use line above, does not insert 
 generic foo
 }


 void main()
 {
 	iA a = new A;
 	a.foo(a);
 	(cast(A)a).foo(cast(A)a);
 	(cast(A)a).foo(a);  // line doesn't work when using mixin 
 template because the generic foo does not exist
 }


 This seems like a bug to me but maybe that's how mixin 
 templates work? If so is there any way to make them insert the 
 code regardless if it thinks they are the same? (they are not 
 in this case and I need to use them to reduce redundancy)

functions introduced through mixin templates do not take part in overload resolution when an overload exists outside the mixin. It's a common annoyance, I can't remember if there's a good reason for it.

This seems to be the problem. The mixin thinks they are the same function so it doesn't insert it. I guess it just looks at the name rather than the complete signature. Would be real nice if that wasn't the case or if one could chose the behavior. I can see in some cases it being nice to have the current behavior but not all(specifically talking about overloads).
Mar 07 2014
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 03/07/14 20:22, Frustrated wrote:
 On Friday, 7 March 2014 at 09:10:45 UTC, John Colvin wrote:
 functions introduced through mixin templates do not take part in overload
resolution when an overload exists outside the mixin.
 It's a common annoyance, I can't remember if there's a good reason for it.

This seems to be the problem. The mixin thinks they are the same function so it doesn't insert it. I guess it just looks at the name rather than the complete signature. Would be real nice if that wasn't the case or if one could chose the behavior. I can see in some cases it being nice to have the current behavior but not all(specifically talking about overloads).

You can explicitly add the function(s) to the overload set, ie mixin template some_mixin_templ() { void f() {} } struct S { mixin some_mixin_templ blah; void f(int) {} alias f = blah.f; // add the one(s) from the mixin template } or use a string mixin (which is less problematic inside a /mixin/ template): mixin template some_mixin_templ(string CODE="") { void f() {} mixin (CODE); } struct S { mixin some_mixin_templ!q{ void f(int) {} }; } artur
Mar 26 2014
prev sibling parent "Frustrated" <Who where.com> writes:
On Wednesday, 26 March 2014 at 19:29:49 UTC, Artur Skawina wrote:
 On 03/07/14 20:22, Frustrated wrote:
 On Friday, 7 March 2014 at 09:10:45 UTC, John Colvin wrote:
 functions introduced through mixin templates do not take part 
 in overload resolution when an overload exists outside the 
 mixin.
 It's a common annoyance, I can't remember if there's a good 
 reason for it.

This seems to be the problem. The mixin thinks they are the same function so it doesn't insert it. I guess it just looks at the name rather than the complete signature. Would be real nice if that wasn't the case or if one could chose the behavior. I can see in some cases it being nice to have the current behavior but not all(specifically talking about overloads).

You can explicitly add the function(s) to the overload set, ie mixin template some_mixin_templ() { void f() {} } struct S { mixin some_mixin_templ blah; void f(int) {} alias f = blah.f; // add the one(s) from the mixin template } or use a string mixin (which is less problematic inside a /mixin/ template): mixin template some_mixin_templ(string CODE="") { void f() {} mixin (CODE); } struct S { mixin some_mixin_templ!q{ void f(int) {} }; } artur

This is not really any better than just using a string mixin directly. You have to create a named mixin then create the aliases. In your example, you know the function being mixed in so it is easy. In my case, the function name was generated by a string mixin. So I'd basically have to have to mixins, one to generate the function itself and the other to generate the aliases, then I've have to call them both in the struct. Much worse than just passing the typeof(this) to the string mixin. The only way it could work is if I could use the alias inside the template mixin and it all work out. In any case, it's a very convoluted way to achieve what I want(which is simply not having to pass typeof(this) to the string mixin).
Mar 28 2014