DIP66 - Multiple alias this

Mike slavo5150 at yahoo.com
Wed Sep 30 01:36:59 UTC 2020


On Monday, 28 September 2020 at 19:55:10 UTC, Andrei Alexandrescu 
wrote:

> I'd love to get a better idea about this, e.g. a few clear 
> examples of bad uses and other few good examples where it's a 
> win. My intuition vaguely revolves around "aliasing to an 
> rvalue is bad and lvalue is good" but I year for clarity.

What's good about `alias this`
------------------------------
`alias this` is used for 2 primary purposes:

1.  Forwarding a member's interface to its containing object's 
interface
2.  Implicit casting and subtyping which are fundamentally 
different but with similar use cases

```
struct A { int x; }

struct B
{
     A a;
     alias a this;
     int y;
}

void PassA(A a) {}

void main()
{
     B b;
     int i = b.x;  // A.x was forwarded through B
     int j = b.y;
     PassA(b);     // B was implicitly cast to A
}
```

`alias this` is actually useless for classes, because the same 
thing can be achieved with inheritance:

```
class A { int x; }

class B : A
{
     int y;
}

void PassA(A a) {}

void main()
{
     auto b = new B();
     int i = b.x;  // A.x was forwarded through B
     int j = b.y;
     PassA(b);     // B was implicitly cast to A
}
```

What's bad about `alias this`
-----------------------------
Walter addressed the problem with `alias this` here:

> If a class hierarchy has alias this, when does the compiler go 
> looking down the alias this, and when does it go looking at the 
> base class and interfaces? (Of course the base class can have 
> an alias this, and an alias this can have a base class.) You 
> have essentially *two* multiple inheritance systems in play at 
> the same time, each obeying different rules.

> Couple that with the current arbitrary random rules about how 
> alias this behaves for classes, and any coherent MI alias this 
> scheme would randomly break existing code.

In other words, its too complex, and adding multiple `alias this` 
would only compound that complexity.

My 2 cents
----------
`alias this` is useless for classes unless users want to abuse it 
to create "dual" inheritance by both inheriting from another 
class, and `alias this` a member simultaneously.  Just use 
inheritance.  If you need multiple inheritance, inherit from 
multiple interfaces and use D's excellent metaprogramming 
facilities to auto-implement each interface, or auto-forward 
members that implement the interfaces.

```
interface A { @property int x(); }
mixin template Aimp()
{
     @property int x() { return 0; }
}

interface B { @property int y(); }
mixin template Bimp()
{
     @property int y() { return 0; }
}

class C : A, B
{
     mixin Aimp;
     mixin Bimp;
}

void PassA(A a) {}

void PassB(B b) {}

void main()
{
     auto c = new C();
     int i = c.x;  // A's implementation in C
     int j = c.y;  // B's implementation in C
     PassA(c);     // C implicitly cast to A
     PassB(c);     // C implicitly cast to B
}
```

Where `alias this` has no alternative for structs because structs 
cannot inherit and cannot implement interfaces.  D has sufficient 
metaprogramming facilities to auto-forward members, but the 
missing piece is implicit casting.

```
mixin template Aimp()
{
     int x;
}

mixin template Bimp()
{
     int y;
}

struct C
{
     mixin Aimp;
     mixin Bimp;
}

void PassA(A a) {}  // Error:  What do we put here when we want a 
type that implements `A`.  There is no such type?

void PassB(B b) {}  // Error:  What do we put here when we want a 
type that implements `B`,  There is no such type?

void main()
{
     auto c = new C();
     int i = c.x;  // A's implementation in C
     int j = c.y;  // B's implementation in C
     PassA(c);     // Error:  C cannot implicitly cast to A
     PassB(c);     // Error: C canot implicitly cast to B
}
```

So, here are a couple of proposals off the top of my head.  I 
imagine someone more talented than I can think of a few more:

1.  Deprecate `alias this` for classes, and implement multiple 
`alias this` for structs.  That will give users the composition 
feature they need, and in addition, because structs cannot 
inherit, it removes the complexity Walter spoke of.

2.  Add `opImplicit`, implicit copy constructors, or something of 
that ilk.  Then users only need to forward members using D's 
metaprogramming facilities.  Both uses of `alias this` are 
covered, but no `alias this` is required.  `alias this` can then 
be deprecated entirely.

3.  Add struct inheritance like C++.


More information about the Digitalmars-d mailing list