December 21, 2014
On Saturday, 20 December 2014 at 23:22:40 UTC, Joseph Rushton Wakeling via Digitalmars-d wrote:
> On 02/11/14 15:55, IgorStepanov via Digitalmars-d wrote:
>> http://wiki.dlang.org/DIP66
>>
>> I've applied some changes to it, however there are still some unresolved questions.
>
> The current DIP doesn't address protection attributes.  I recognize this might be somewhat orthogonal, but it'd be nice to build it into the DIP if possible, just to be explicit about what is expected for how alias this should work.
>
> According to TDPL the following should work:
>
>     struct Foo
>     {
>         private T internal_;         // member variable is private
>
>         public alias internal_ this; // .. but can be interacted with
>                                      // via the public alias
>     }
>
> It seems to me an important factor, because it means that classes and structs can use subtyping without revealing the implementation details.  As things are, you wind up having to do something like,
>
>     struct Integer
>     {
>         private int i_;
>
>         public ref int getInteger() @property
>         {
>             return i_;
>         }
>
>         alias getInteger this;
>     }
>
> ... which personally I find a bit of an unpleasant violation of the idea of a private implementation.
>
> See also: https://issues.dlang.org/show_bug.cgi?id=10996

I have nothing against this, but this is, indeed, completely out of the scope (!) of the DIP.
December 21, 2014
On Sunday, 21 December 2014 at 08:23:34 UTC, deadalnix wrote:
>> See also: https://issues.dlang.org/show_bug.cgi?id=10996
>
> I have nothing against this, but this is, indeed, completely out of the scope (!) of the DIP.

I think it belongs to DIP22
December 22, 2014
On 21/12/14 11:11, Dicebot via Digitalmars-d wrote:
> On Sunday, 21 December 2014 at 08:23:34 UTC, deadalnix wrote:
>>> See also: https://issues.dlang.org/show_bug.cgi?id=10996
>>
>> I have nothing against this, but this is, indeed, completely out of the scope
>> (!) of the DIP.
>
> I think it belongs to DIP22

In fact it's already in there:

    A public alias to a private symbol makes the symbol
    accessibly through the alias. The alias itself needs
    to be in the same module, so this doesn't impair
    protection control.

It's just not implemented for alias this.
December 22, 2014
On 21/12/14 09:23, deadalnix via Digitalmars-d wrote:
> I have nothing against this, but this is, indeed, completely out of the scope
> (!) of the DIP.

Fair enough.  I wanted to make sure there was nothing here that could interact nastily with protection attributes.

December 23, 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.
December 24, 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.

December 24, 2014
On 12/23/14 8:54 PM, Walter Bright wrote:
>
> 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).

Though I agree it makes sense to just return false, I think it would be more sensible and useful to issue an error. If B is reachable from B through multiple paths, that's a new situation distinct from yes/no.

In fact a better thought: as soon as D is defined, repeated subtyping should be detected as an error. Then there's no question about "is" in the first place :o).


Andrei

December 24, 2014
On Wednesday, 24 December 2014 at 06:17:28 UTC, Andrei Alexandrescu wrote:
> In fact a better thought: as soon as D is defined, repeated subtyping should be detected as an error. Then there's no question about "is" in the first place :o).
>
>
> Andrei

Agreed. How about using "override alias this" when disambiguating, in order to make it more explicit?

struct C
{
  alias a this;
  alias b this;
  override alias b.i this; // override inherited alias int this.
  A a;
  B b;
}
December 24, 2014
On 12/24/14 12:58 AM, Daniel Nielsen wrote:
> On Wednesday, 24 December 2014 at 06:17:28 UTC, Andrei Alexandrescu wrote:
>> In fact a better thought: as soon as D is defined, repeated subtyping
>> should be detected as an error. Then there's no question about "is" in
>> the first place :o).
>>
>>
>> Andrei
>
> Agreed. How about using "override alias this" when disambiguating, in
> order to make it more explicit?
>
> struct C
> {
>    alias a this;
>    alias b this;
>    override alias b.i this; // override inherited alias int this.
>    A a;
>    B b;
> }

Is there a need for explicit overriding, i.e. any inadvertent error people may make without it? -- Andrei
December 26, 2014
On Wednesday, 24 December 2014 at 22:09:49 UTC, Andrei Alexandrescu wrote:
> Is there a need for explicit overriding, i.e. any inadvertent error people may make without it? -- Andrei

I failed to find any dangerous refactoring sequences, so it might be superfluous, however I found another minor issue, see below.

Anyway considering the new ways of working, when using the -dip switch for the initial few releases, there is ample time to perfect all details.

// Example 1
struct A {int i;alias i this;}
struct Z
{
  A a;
  alias a   this;
}

// A is preferred since it requires only one implicit conversion.
void process(A)   {}
void process(int) {}

// Example 2
struct A {int i;alias i this;}
struct B {int i;alias i this;}
struct Z
{
  A a;
  B b;
  alias a   this;
  alias b   this;
  alias a.i this;
}

// The below is now ambiguous because Z is directly convertible to 'int' although we only intended to disambiguate between Z->A->int and Z->B->int
void process(A)   {}
void process(int) {}