Ambiguous virtual function

Adam D. Ruppe destructionator at gmail.com
Thu Dec 6 14:12:50 UTC 2018


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.



More information about the Digitalmars-d-learn mailing list