Spec: Mixin Scope
The declarations in a mixin are 'imported' into the surrounding scope. If the name of a declaration in a mixin is the same as a declaration in the surrounding scope, the surrounding declaration overrides the mixin one.
---
Mixins should not only compare name with existing symbols in current scope, but in case of functions also parameters. It will allow proper function overloading. Currently following test case fails to compile:
import std.stdio;
template TestTemplate(T) {
T policy(int i) { return T.init;}
int policy() { return 1; }
}
class TestClass {
mixin TestTemplate!(TestClass);
TestClass policy(int i) { return this; }
}
void main() {
writefln((new TestClass).policy);
}
---
It is quite painful limitation of mixins, and IMHO should be bug. I put it as enhancement because it conforms literal interpretation of specs.
Comment #1 by bugzilla — 2007-04-24T04:02:55Z
It isn't a bug, it's meant to behave this way. If you want to overload mixin names with the surrounding scope name, you can use an 'alias' in the same manner one would use alias to merge the overload sets of two imported modules.
Comment #2 by aarti — 2007-04-24T04:40:47Z
How to make alias definition with anonymous mixin and function?
I can understand how to do it with named mixins but with my example? I
did not found similar example here on NG...
Could you please just correct my test case? One example is worth more
than thousand words... :-)
Comment #3 by bugzilla — 2007-04-24T05:21:56Z
You can't do it with anonymous mixins, they have to be named.
import std.stdio;
template TestTemplate(T) {
T policy(int i) { return T.init;}
int policy() { return 1; }
}
class TestClass {
mixin TestTemplate!(TestClass) foo;
alias foo.policy policy;
TestClass policy(int i) { return this; }
}
void main() {
writefln((new TestClass).policy);
}
Comment #4 by aarti — 2007-04-24T05:45:27Z
First: How does it work? There are two policy symbols in template
(overloaded functions). Why 'getter property' is choosen? How to choose
setter?
Second: That's solution far from good. Imagine you have e.g. 10 symbols
inserted by mixin (I work with such a case.). What's more mixins are
inserted into many inherited classes. You need to alias all symbols
inside mixin template in every inherited class.
Third: Would be also great to implement anchored types (#1120). It would
depreciate this use-case for mixins.
I request to leave that enhancement open. Simply enhancing rule of
inserting anonymous mixin into scope for function names *AND* their
arguments would solve problem cleanly.
Comment #5 by aarti — 2007-04-24T06:39:01Z
Maybe I was not enough clear with my enhancement idea. I think that original test case doesn't work because when compiler is mixing in template, it checks if symbol 'policy' exists. According to specs when in current scope symbol exists, symbol from mixin template should be dropped. It works good in general case (and is really useful), but doesn't work in my example. When checking for symbol compiler just doesn't check parameters of function and thinks that symbol 'policy' is already there. If checking symbol could also include checking parameters, method from template:
int policy() { return 1; }
could be normally inserted in the scope of TestClass. (But method T policy(int i) { return T.init;} from template would be still droped, as it is *exactly* same as in TestClass scope.)
Comment #6 by aarti — 2007-04-27T02:34:46Z
It seems that your example works just because there is template function used. In general case it fails, so it is no solution to problem. Consider following example:
import std.stdio;
template TestTemplate() {
int policy() { return 0; }
int policy(int a) { return 1;}
int policy(int a, int b) { return 2;}
}
class TestClass {
mixin TestTemplate!() foo;
alias foo.policy policy;
int policy(int a) { return 11; }
}
void main() {
writefln((new TestClass).policy); //(1) Ok.
//writefln((new TestClass).policy(1)); //(2) ambiguity
writefln((new TestClass).policy(1,1)); //(3) Ok.
}
It would be possible to overcome this if you could alias specific symbol /method e.g.:
alias foo.policy(int, int) policy;
It seems that best solution is to extend rules of symbol matching. I would be happy to see it also in case of inheritance (see thread on bugs NG).
Comment #7 by razvan.nitu1305 — 2019-08-12T11:58:51Z
(In reply to Marcin Kuszczak from comment #4)
> First: How does it work? There are two policy symbols in template
> (overloaded functions). Why 'getter property' is choosen? How to choose
> setter?
>
Because the overload that does not take any parameters is called. If you would
call the other it would be an ambiguity error (as it should).
> Second: That's solution far from good. Imagine you have e.g. 10 symbols
> inserted by mixin (I work with such a case.).
You can use metaprogramming to generate the aliases.
>What's more mixins are
> inserted into many inherited classes. You need to alias all symbols
> inside mixin template in every inherited class.
>
You would most likely get errors regarding overriding.
> Third: Would be also great to implement anchored types (#1120). It would
> depreciate this use-case for mixins.
>
> I request to leave that enhancement open. Simply enhancing rule of
> inserting anonymous mixin into scope for function names *AND* their
> arguments would solve problem cleanly.
That will probably never happen. That would break code and it would make the mixin model inconsistent with the import one and we don't want that. This design has served us well and there is no reason to change it, since there are workarounds for all the situations stated in the enhancement request.
Closing as WONTFIX.