DIP66 v1.1 (Multiple) alias this.

Walter Bright via Digitalmars-d digitalmars-d at puremagic.com
Tue Dec 23 20:54:27 PST 2014


On 12/23/2014 10:42 AM, IgorStepanov wrote:
> 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.

Ok, let's make it an error.


>> 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 current behavior of:

     is (D : B)

is the expression will evaluate to false if D does not compile. However, a 
compile time error will be issued if B does not compile.

If D and B compile, then it will evaluate to false if B is not implicitly 
convertible to D. This suggests to me Option 1, i.e. if the implicit conversion 
fails due to ambiguity errors, then it should return false (not issue a compile 
time error).

I'm not sure what you mean by "absorb the real error".


>> 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