Thread overview
passing member.member alias to mixin template
Sep 03, 2017
Eric_DD
Sep 03, 2017
ag0aep6g
Sep 03, 2017
Eric_DD
September 03, 2017
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;
}

September 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`.
September 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