DIP66 v1.1 (Multiple) alias this.

IgorStepanov via Digitalmars-d digitalmars-d at puremagic.com
Tue Dec 23 10:42:55 PST 2014


On Saturday, 20 December 2014 at 21:25:28 UTC, Andrei 
Alexandrescu wrote:
> On 11/2/14 6:57 AM, IgorStepanov wrote:
>> And there is dispute about is expression: see
>> http://forum.dlang.org/thread/ubafmwvxwtolhmnxbrsf@forum.dlang.org?page=5
>
> OK, time to get this approved.
>
> First, the current DIP doesn't seem to address this:
>
>> Walter and I would agree to making the presence of BOTH alias 
>> this
>> and opDispatch a compile-time error. That would break existing 
>> code
>> but not change semantics silently.

Far as I remember it was left to the discussion. Nobody objected 
to this issue, thus we may accept it. I think.

> Any thoughts on this? Currently opDispatch gets priority over 
> alias this, see lookup step 3 in section "Semantics" of 
> http://wiki.dlang.org/DIP66. That's problematic because it puts 
> opDispatch in _between_ "normal" subtyping via inheritance and 
> alias this, which is supposed to be just as solid as 
> inheritance.
>
> I think the principled solution is to combine steps 2 and 4 
> into step 2, i.e. alias this is as strong as inheritance. Any 
> ambiguous symbols would be rejected.
>
> The second possibility, less principled but probably practical, 
> would be to swap steps 3 and 4. That way alias this has juuust 
> a teensy bit a lower status than regular inheritance.

It looks nice, but it can greatly break the existing code. I 
suggest a postpone this issue and discuss the semantic order in a 
separate discusson/

> The simplest thing (which Walter favors) is to make the 
> presence of both opDispatch and alias this a compile-time 
> error. That would break only a teensy amount of code if any, 
> and would give us time to investigate the best approach when 
> compelling use cases come about. So I suggest we move forward 
> with that for this DIP.
>
> Regarding the is-expression controversy in 
> http://forum.dlang.org/thread/ubafmwvxwtolhmnxbrsf@forum.dlang.org?page=5:
>
> First off, is(S : T) is a subtyping test - is S a non-proper 
> subtype of T, or not? (Non-proper or improper subtyping: S is 
> allowed to be identical to T). "alias this" is a mechanism that 
> introduces subtyping. It follows that subtyping introduced via 
> "alias this" must be detected with is-expressions.
>
> Now, you give an example of subtyping where one or more two 
> objects of the same supertype may be reached through two or 
> more different paths. This is a well-known problem in subtyping 
> (known as diamond hierarchy or repeated inheritance).
>
> In the case of "alias this", different objects of the same type 
> may be reachable (or at least the compiler is unable to tell 
> statically whether the objects are distinct or not). A correct 
> but hamfisted solution would be to sever the subtyping 
> relationship whenever the same type is reachable through 
> multiple paths.
>
> The versatility of "alias this", however, suggests a better 
> solution: if T is indirectly reachable as a supertype of S 
> through more than one path and the subtyping is either tested 
> (by means of an is-expression) or effected (by means of an 
> implicit conversion), the compiler should issue a compile-time 
> error asking the user to define an "alias this" DIRECTLY inside 
> S, which takes precedence over indirect reachability and 
> informs the type system which T of the several reachable ones 
> is needed.
>
> Please let me know of any thoughts. Thanks!

Summing up.
There are three way to process is(D: B) where D may be converted 
to B in several ways.
1. is(D: B) should return false: D is not subtype of B now.
2. is(D: B) should return true: D is subtype of B anyway.
3. is(D: B) should raise an error: let the user decide what he 
wants.

I strongly aganist the first way. It means that is(D: B) may 
absorb the real error, if it happens.
Now only two construction in D may absorb errors:
is(typeof(something)) and __traits(compiles, anything)).
I say "absorb" when compiler see the error, ignores it and 
changes way of compilation:
static if (<noErrors>)
     <correct branch>
else
     <error branch>

This situation may cause strage errors, code hijacking and other 
bad things, thus user should has a possibility to keep track of 
such cases.
is(typeof(something)) and __traits(compiles, anything)) is a 
special constructions to error handling and user and everyone 
understands what is expected.
is(D: B) is trusted construction and it can't create problems 
now. Let's leave it so.

The second way is better, I think. It doesn't absorb the error, 
it skip error but doesn't change the compilation way.
Error will be raised anyway when compiler will process code which 
use this casting.
void foo(D)(D obj) if (is(D: Base)) // compiler will skip the 
error here...
{
     Base b = obj; //... but it will raise the error here.
}

The third way is correct too, I think. It raises error earlier, 
but I changes current `is` semantic. AFAIK, `is` doesn't raise 
errors now.

>the compiler should issue
>a compile-time error asking the user to define an "alias this" 
>DIRECTLY
>inside S, which takes precedence over indirect reachability and 
>informs
>the type system which T of the several reachable ones is needed.

That means that user should may override inherited alias this 
declarations:

struct A
{
     alias i this;
     int i;
}

struct B
{
     alias i this;
     int i;
}

struct C
{
     alias a this;
     alias b this;
     alias b.i this; //override inherited alias int this.
     A a;
     B b;
}

It was implemented in my first implementation, but AFAIR you 
suggested delay it for postpone this feature and introduce it 
later. Thus now I remove this option from PR and DIP, but I may 
revert it back.

P.S. sorry for big latency, it will take place within a couple of 
months, but I will do this work anyway.


More information about the Digitalmars-d mailing list