digitalmars.D.learn - passing member.member alias to mixin template
I am running into something that seems a bit inconsistent. When I pass an alias of a member to a mixin it works, but a member to member doesn't. It seems like the alias is evaluated to the last symbol before passing it to the mixin. If that's true, is there a way to defer the evaluation? Anyway, better look at this code: *** This works: struct Array { void foo() { writeln("foo"); } } mixin template arrayOperations(arrays...) { void foo() { foreach(ref a; arrays) a.foo(); } } class Thing { Array data1; Array data2; mixin arrayOperations!(data1, data2); } int main(string[] argv) { new Thing().foo(); return 0; } *** But if I wrap Array in a S, then I get a "need this for data of type Array" Is there a way (without an alias this in S) to get the following working? *** Non working code: struct Array { void foo() { writeln("foo"); } } struct S { Array data; } mixin template arrayOperations(arrays...) { void foo() { foreach(ref a; arrays) a.foo(); // error: "need this for data of type Array" } } class Thing { S s1; S s2; mixin arrayOperations!(s1.data, s2.data); } int main(string[] argv) { new Thing().foo(); return 0; }
Sep 03 2017
On 09/03/2017 08:54 PM, Eric_DD wrote:*** This works: struct Array { void foo() { writeln("foo"); } } mixin template arrayOperations(arrays...) { void foo() { foreach(ref a; arrays) a.foo(); } } class Thing { Array data1; Array data2; mixin arrayOperations!(data1, data2); }[...]*** But if I wrap Array in a S, then I get a "need this for data of type Array" Is there a way (without an alias this in S) to get the following working? *** Non working code:[...]struct S { Array data; }[...]class Thing { S s1; S s2; mixin arrayOperations!(s1.data, s2.data); }As far as I understand, the problem is that an alias of a member does not carry a `this` reference. It's added only when you use the alias in a method of the aggregate. That means, s1.data is not an alias of s1's `data` field, but an alias of `S.data`. And so is `s2.data`. They're effectively the same alias. It's the same with `data1` and `data2`. But in that case the aliases work because `foo` provides the correct `this` reference. An example of what I mean: ---- import std.stdio; class C { int field; void method() { writeln(f); } } C c1; C c2; alias f = c1.field; void main() { c1 = new C; c2 = new C; c1.field = 1; c2.field = 2; c1.method(); /* prints "1" */ c2.method(); /* prints "2" */ version (none) writeln(f); /* Error: need 'this' */ } ---- Note that `c2.method()` prints "2", even though the alias f has been made from c1. The alias doesn't refer to c1's specific field, but to the generic field of the C class. The alias can only be used in methods of C, because they provide the needed `this`.
Sep 03 2017
Clear explanation, thanks! I think it would avoid a lot of confusion to disallow the alias f = c1.field notation and only allow the alias f = C.field notation. If necessary one could use alias f = typeof(c1).field
Sep 03 2017