digitalmars.D.learn - Mixin template overloads not working
- Rumbu (24/24) Dec 03 2021 ```d
- Stanislav Blinov (2/7) Dec 03 2021
- Rumbu (14/21) Dec 07 2021 Yes, I know, but in fact the compiler wrongly assumes that
- Steven Schveighoffer (22/37) Dec 07 2021 It doesn't have to do with mangling. It has to do with implicit conversi...
- Q. Schroll (5/7) Dec 07 2021 Feature. It even has a name: "overload set". It keeps you from
- Steven Schveighoffer (67/73) Dec 07 2021 Not in this case. See this demonstration (I removed irrelevant pieces):
```d class S {} class A:S {} class B:S {} mixin template vmix(T) { void visit(T t) {} } class Visitor { void visit(S s) {} mixin vmix!A; mixin vmix!B; } class AnotherVisitor: Visitor { override void visit(A a) {} } ``` This will result in error when I try to override mixin generated visit(A) in AnotherVisitor. If A doesn't inherit S, the override in AnotherVisitor works like a charm. Bug or feature? Is there any workaround?
Dec 03 2021
On Friday, 3 December 2021 at 10:42:37 UTC, Rumbu wrote:Bug or feature? Is there any workaround?The error message explains what to do :)Error: class `mixinover.AnotherVisitor` use of `mixinover.Visitor.visit(S s)` is hidden by `AnotherVisitor`; use `alias visit = Visitor.visit;` to introduce base class overload set
Dec 03 2021
On Friday, 3 December 2021 at 10:57:34 UTC, Stanislav Blinov wrote:On Friday, 3 December 2021 at 10:42:37 UTC, Rumbu wrote:Yes, I know, but in fact the compiler wrongly assumes that visit(A) is hiding visit(S). visit(A) is just an overload, it has a different signature than visit(S), theoretically the compiler must mangle it using a different name. Finally I solved it by "finalizing" visit(S), so it's not taken into overrides set. ```d class Visitor { final void visit(S s) {} //... }Bug or feature? Is there any workaround?The error message explains what to do :)Error: class `mixinover.AnotherVisitor` use of `mixinover.Visitor.visit(S s)` is hidden by `AnotherVisitor`; use `alias visit = Visitor.visit;` to introduce base class overload set
Dec 07 2021
On 12/7/21 7:43 AM, Rumbu wrote:On Friday, 3 December 2021 at 10:57:34 UTC, Stanislav Blinov wrote:It doesn't have to do with mangling. It has to do with implicit conversions. A more classic example would be: ```d class A { void foo(long i) {} void foo(int i) {} } class B : A { override void foo(long i) {} } ``` This hides A.foo(int), because B.foo(int) will call the long overload instead, when you might expect it to call the base class int overload. But I agree with you that this seems like a bug -- the anti-hidden overload error is supposed to complain when you have an implicitly convertible parameter. In this case, you aren't hiding visit(S) because visit(A) would not accept an S. The spec's explanation is pretty poor (and has invalid demo code to boot). -SteveOn Friday, 3 December 2021 at 10:42:37 UTC, Rumbu wrote:Yes, I know, but in fact the compiler wrongly assumes that visit(A) is hiding visit(S). visit(A) is just an overload, it has a different signature than visit(S), theoretically the compiler must mangle it using a different name.Bug or feature? Is there any workaround?The error message explains what to do :)Error: class `mixinover.AnotherVisitor` use of `mixinover.Visitor.visit(S s)` is hidden by `AnotherVisitor`; use `alias visit = Visitor.visit;` to introduce base class overload set
Dec 07 2021
On Tuesday, 7 December 2021 at 12:43:40 UTC, Rumbu wrote:Bug or feature?Feature. It even has a name: "overload set". It keeps you from accidentally calling a function you had no idea existed, for example because of a name clash.Is there any workaround?Yes, the error message is very clear.
Dec 07 2021
On 12/7/21 1:03 PM, Q. Schroll wrote:On Tuesday, 7 December 2021 at 12:43:40 UTC, Rumbu wrote:Not in this case. See this demonstration (I removed irrelevant pieces): ```d class S {} class A:S {} class Visitor { void visit(S s) {} void visit(A a) {} } class Derived : Visitor { } void main() { auto v = new Derived; v.visit(A.init); // calls visit(A) v.visit(S.init); // calls visit(S) } ``` Now, let's add a supposed "hiding" function: ```d class Derived : Visitor { override void visit(A a) {} } ``` Now, we have these 2 lines: ```d v.visit(A.init); // works, calls visit(A), just like before v.visit(S.init); // fails to compile, no overload for S. ``` Where is the hidden function? If you are thinking that just because it's not brought forth in the overload set, that's not important. Change the two visit parameters to string and int, and it compiles just fine: ```d class Visitor { void visit(string s) {} void visit(int a) {} } class Derived : Visitor { override void visit(int a) {} // no problem, even though we don't cover the string case } ``` NOW, if you did instead: ```d class Derived : Visitor { override void visit(S s) {} } ``` Now there is a hidden function, because visit(A.init) is going to call the derivative visit(S), whereas before it would call Visitor.visit(A). But that isn't this case. The spec says: "It is illegal if, through implicit conversions to the base class, those other functions do get called." The spec does not seem to cover this case, and the rules it states are not exactly what the compiler currently implements. I'm not sure where the bug is -- spec or implementation -- but there is a disagreement for sure. It's telling that making the S-accepting function final will fix the problem. -SteveBug or feature?Feature. It even has a name: "overload set". It keeps you from accidentally calling a function you had no idea existed, for example because of a name clash.
Dec 07 2021