June 13, 2022

On Monday, 13 June 2022 at 12:03:10 UTC, Max Samukha wrote:

>

On Monday, 13 June 2022 at 10:55:36 UTC, Ola Fosheim Grøstad wrote:

>

On Monday, 13 June 2022 at 10:51:10 UTC, Mike Parker wrote:

>

And I'm arguing that this is exactly what we should expect from private-to-the-module, since B is not declared in the same module as the superclass, so it's neither unfinished nor a bug.

It breaks the sub-typing requirement.

If you get more access by recasting a pointer to the super-type then the sub-typing relation cannot be satisfied.

And the reason is the private member of the class shouldn't be accessible outside its declaration scope in the first place. Module-level 'private' is dysfunctional by design.

>

Hence, it is certainly broken. If it is not a bug, then it is broken by design. Which is no better.

I honestly don't have a problem with module-level private, but I do have a problem with inconsistency and ignorance.

D argues so much about being module-level private, but it really isn't.

June 13, 2022
On Monday, 13 June 2022 at 03:46:52 UTC, Mike Parker wrote:
> [snip]
> This is the reason I think it's a useless feature. If you have access to the module, you have access to the internal members of the class. It's no different than having a class per file in Java. At some point, it comes down to coding conventions (e.g., all internal access to private members within a Java class must explicitly go through the public interface).
>
> How does this feature bring any benefit that can't be had by putting `Foo` in a separate module? That's the question you have to answer.

A fair point, but one of the arguments (over who knows how many pages at this point...) is that some people want to be able to have some way to ensure that the only way to access internal members is controlled through the class itself. You would reply that there is an alternative, which is to put that class in a separate module. It is a little like @safe (in a project with no dependencies, is @safe useless because the programmer has access to all the code and can verify themselves whether there are any errors?). Some people want guarantees. The people arguing for this want the guarantee that if they write some other function *in the module* that tries to access one of this internal members, then they get an error. Now, that's not something that has been a concern to me, but I don't necessarily think it is a useless feature.
June 13, 2022

On Monday, 13 June 2022 at 12:03:10 UTC, Max Samukha wrote:

>

And the reason is the private member of the class shouldn't be accessible outside its declaration scope in the first place. Module-level 'private' is dysfunctional by design.

It can be fixed, but I personally prefer granting other entities «roles».

C++ friend-mechanism is one variant of granting "roles". For instance if you make the class MedicalRole a friend of the class Brain then you can make BrainSurgeon a subclass of MedicalRole which grants the BrainSurgeon access to the internals of Brains. Since C++ has multiple inheritance it follows that you can design your own role-granting regime in C++ if you want to.

(I personally prefer to only grant access to individual functions because it is tighter, but the concept of class based roles is easier to deal with when debugging/remodelling than the concept of package.)

June 13, 2022

On Monday, 13 June 2022 at 12:16:28 UTC, zjh wrote:

>

No! We don't need encapsulation!
We are all friends.
Your variable, I will use it if I want to!You should happy however I use it,we are friends!

We should put all the modules in one file, so that there will be more friends!

June 13, 2022

On Monday, 13 June 2022 at 12:34:56 UTC, Ola Fosheim Grøstad wrote:

>

On Monday, 13 June 2022 at 12:03:10 UTC, Max Samukha wrote:

>

And the reason is the private member of the class shouldn't be accessible outside its declaration scope in the first place. Module-level 'private' is dysfunctional by design.

It can be fixed, but I personally prefer granting other entities «roles».

C++ friend-mechanism is one variant of granting "roles".

I guess it is worth adding that one weakness in C++ (and D) is that functions are not objects (in contrast to Beta). If functions were objects and if the called function could inspect the caller's object-type then you could design a much more advanced regime and create interesting novel framework-mechanisms using meta-programming.

June 13, 2022

On Monday, 13 June 2022 at 08:44:59 UTC, bauss wrote:

>

On Monday, 13 June 2022 at 08:07:05 UTC, Mike Parker wrote:

>

But why should that compile? You're trying to manipulate _c through an instance of Bar. It's not visible in any Bar, ever, so why should it be visible here? It has to be gotten at through the interface of Foo.

Because I'm in the module of a, _c is a member if Foo, Foo is in a.

Thus _c should be accessible within a regardless of whether it's public within the b module or not.

_c is accessible; you just have to use the syntax child.Foo._c to access it. This is documented in the language spec:

>

Members of a base class can be accessed by prepending the name of the base class followed by a dot

https://dlang.org/spec/class.html#fields

This is necessary because D allows you to define fields with the same name in a base class and its derived class; for example:

class Base
{
    int x = 123;
}

class Derived : Base
{
    int x = 456;
}

void main()
{
    auto instance = new Derived;
    assert(instance.x == 456);
    assert(instance.Base.x == 123);
}
June 13, 2022

On Monday, 13 June 2022 at 13:51:40 UTC, Paul Backus wrote:

> >

This is necessary because D allows you to define fields with the same name in a base class and its derived class; for example:

This is horrifying, one of the darkest corner of D.

>
class Base
{
    int x = 123;
}

class Derived : Base
{
    int x = 456;
}

void main()
{
    auto instance = new Derived;
    assert(instance.x == 456);
    assert(instance.Base.x == 123);
}
June 13, 2022

On Monday, 13 June 2022 at 13:51:40 UTC, Paul Backus wrote:

>

This is necessary because D allows you to define fields with the same name in a base class and its derived class;

Hardly necessary, C++ will error on this:

class A {
    int x=1;
    friend int main();
};

class B  : public  A {
    int x=4;
};


int main()
{
    B obj{};
    cout << obj.x;
}

But allow this:

class A {
    int x=1;
    friend int main();
};

class B  : public  A {
    int y=4;
};


int main()
{
    B obj{};
    cout << obj.x;
}

Of course, since C++ has multiple inheritance it has to deal with conflicts. D forbid it, although I guess you could argue that the subclass should not be affected by naming of fields in the superclass.

I still prefer that this is not allowed as shadowing in class hierarchies makes debugging so much more confusing.

June 13, 2022

On Monday, 13 June 2022 at 14:10:48 UTC, mw wrote:

>

On Monday, 13 June 2022 at 13:51:40 UTC, Paul Backus wrote:

> >

This is necessary because D allows you to define fields with the same name in a base class and its derived class; for example:

This is horrifying, one of the darkest corner of D.

Maybe it's no way to change the language now, but I need a warning message when this happens, in case I accidentally redefined such a field, at least with a compiler flag I can check it.

> >
class Base
{
    int x = 123;
}

class Derived : Base
{
    int x = 456;
}

void main()
{
    auto instance = new Derived;
    assert(instance.x == 456);
    assert(instance.Base.x == 123);
}
June 13, 2022

On Monday, 13 June 2022 at 14:15:15 UTC, Ola Fosheim Grøstad wrote:

>

D forbid it, although I guess you could argue

D could forbid it (since it is single inheritance).