www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Ambiguous virtual function

reply John Chapman <johnch_atms hotmail.com> writes:
I get an "ambiguous virtual function" error when I compile this:

   interface I {
     void fun();
   }

   mixin template F() {
     void fun() {}
   }

   class C : I {
     mixin F;
     mixin F;
   }

But the error doesn't occur with this:

   class C : I {
     mixin F;
     void fun() {}
   }

Is the compiler giving the non-mixed-in function special 
treatment?
Dec 05 2018
next sibling parent Dennis <dkorpel gmail.com> writes:
On Thursday, 6 December 2018 at 07:37:12 UTC, John Chapman wrote:
 Is the compiler giving the non-mixed-in function special 
 treatment?
I think you're running into this bug: https://issues.dlang.org/show_bug.cgi?id=19365 I see that it is not limited to operator overloading, in general the overload set directly put into a struct/class completely overrides the overload set from mixin templates. mixin strings seem to work fine, so you can use those as temporary workaround. Example: ``` mixin template F() { int fun(int i) {return i;} } struct S { mixin F; // (1) mixin(`int fun(int i) {return i;}`); // (2) string fun(string s) {return s;} // (3) } void main() { import std.stdio; S().fun(1).writeln(); } ``` With only the mixin template (1) it works, adding an overload (3) breaks it, though adding the string mixin (2) fixes it even though it should be ambiguous with (1).
Dec 06 2018
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 6 December 2018 at 07:37:12 UTC, John Chapman wrote:
 Is the compiler giving the non-mixed-in function special 
 treatment?
Yes, this is by design: https://dlang.org/spec/template-mixin.html#mixin_scope It allows you to have multiple functions in a mixin and override them selectively by repeating the name after the mixin. mixin template Base() { void foo() {} void bar() {} } class Class { mixin Base; // I like the bar from there, but want a custom foo void foo() {} // so I write this and it just works! } If it turns out you do want some of the stuff from the mixin after all, you simply give it a name and reference it: class Class { mixin Base base; void foo() { base.foo(); } } There, I "overrode" foo from the mixin, and also called the version from the mixin, analogous to the regular "super.foo" from plain inheritance. Note that you can still call "obj.bar();" with the renaming - the "mixin Base base" and "mixin Base" are indistinguishable from each other as far as users of your class are concerned. You can also handle overloads this way: class Class { mixin Base base; void foo(int) {} } Here, I want to offer an overload. Normally, this would override ALL "foo" stuff from Base because it works on the basis of the name alone. But you can merge the overload sets with alias: class Class { mixin Base base; void foo(int) {} alias foo = base.foo; } and now they are combined again! Thus foo() and foo(int) are both present in Class. With specialized templates, it doesn't quite work that way, you will get another compile error (they aren't technically function overloads, so it isn't a bug per se, the compiler is following the spec, but I think it might be considered one anyway because you'd kinda expect it to work the same way)... This is what Dennis saw in his bug report. I commented there too, but here's the answer: struct S { mixin Operators ops; int opBinary(string op: "*")(S rhs) {return 2;} int opBinary(string op)(S rhs) { // forward all others to the mixin return ops.opBinary!op(rhs); } } You write an unspecialized version in the top-level thing that calls into the mixin one. It will then do the specialization from there, with the compiler picking the right one from top level if available, or calling the generic fallback to try the next level if possible, or still throwing an error if the operator is indeed not implemented.
Dec 06 2018