June 14, 2022

On Tuesday, 14 June 2022 at 12:57:57 UTC, bauss wrote:

>

Sure Bar wasn't in the same module, but Foo is and Bar inherits from Foo, thus Bar is Foo and Foo has access to _c in Foo's module and thus Bar should have access to Foo's private members in Foo's module, because Bar is Foo.

It's really not that difficult to grasp such a concept.

Will you please stop insulting my intelligence? I understand what you are saying. I'm just asserting that it's wrong.

Bar has the public interface of Foo, true, but it does not have the private one. The private one is internal to Foo, so to get at it through an instance of Bar, then Bar either has to be in the same module as Foo, or you have to convert the instance to a Foo first.

This is core to D's implementation of classes. If you access the private members of a superclass through instances of its subclass in the way that your original example did, then you are opening yourself up to a potential future bug. So the compiler prevents you from doing it and requires you to explicitly do it through the instance.SuperClass.field syntax.

If that behavior were to change so that instance.field works in your example, then we'd be weakening the implementation, not strengthening it.

June 14, 2022

On Tuesday, 14 June 2022 at 12:39:26 UTC, Ola Fosheim Grøstad wrote:

>

You get an error, just like in C++!

Actually I was wrong, you don't get an error in C++. You get the subclass member.

June 14, 2022

On Tuesday, 14 June 2022 at 13:06:02 UTC, Mike Parker wrote:

>

Bar has the public interface of Foo, true, but it does not have the private one. The private one is internal to Foo, so to get at it through an instance of Bar, then Bar either has to be in the same module as Foo, or you have to convert the instance to a Foo first.

This isn't exactly the end of the universe, but I don't see how shadowing public members is better than shadowing private members.

You end up with the same issues. If D was principled about this, should it not prevent shadowing of public members?

As it is, "private" in D is more than an access restriction, you also change the lookup rules.

(Clearly not the end of the world, as you would typically not write such code.)

June 14, 2022

On Tuesday, 14 June 2022 at 12:57:57 UTC, bauss wrote:

>

Sure Bar wasn't in the same module, but Foo is and Bar inherits from Foo, thus Bar is Foo and Foo has access to _c in Foo's module and thus Bar should have access to Foo's private members in Foo's module, because Bar is Foo.

Despite the fact you can access Foo._c, you can't access it through a different path. This is how D's scopes work, and it makes sense. Consider:

module a;

import b;

int x;

void foo()
{
    b.x = 1; // no access to x through b.x, even though the variable is visible in a.
}
module b;

import a;

private alias x = a.x;

File systems work in the same way - you can't access a node via a path going through inaccessible nodes even if the target node is accessible from the current node via other paths.

That is, the module-level 'private' is still bad design, but it works consistently.

June 14, 2022

On Tuesday, 14 June 2022 at 13:35:21 UTC, Max Samukha wrote:

>

On Tuesday, 14 June 2022 at 12:57:57 UTC, bauss wrote:

>

Sure Bar wasn't in the same module, but Foo is and Bar inherits from Foo, thus Bar is Foo and Foo has access to _c in Foo's module and thus Bar should have access to Foo's private members in Foo's module, because Bar is Foo.

Despite the fact you can access Foo._c, you can't access it through a different path.

It isn't necessarily through a different path unless you think that Bar is cloaking Foo, basically redoing everything that is Foo.

So it is a matter of philosophy: do you think that Bar is an extension of Foo? Or do you think that Bar is a shell around Foo?

From a purist OO viewpoint then Bar should be only an addition to Foo with no ability to redefine anything Foo'ish without Foo's consent. (C++ does not belong in this category I think…)

I believe it is a mistake to mix up lookup with access, because it means you cannot give or grant access without having to rewrite code elsewhere. It also makes it more difficult to refactor (move a class from one context to another).

Not really the most pressing issue for D though.

June 14, 2022
On Tuesday, 14 June 2022 at 05:43:49 UTC, forkit wrote:
> So there has been extensive discussions in other threads, around the idea of adding a new 'design constraint feature' to the D programming language.
>
> The design constraint feature, is 'designed' to allow the programmer to make an explicit declaration, that some aspect of the design of a class, should be private to that class, and thereby make that aspect of the class (logically) inaccessible to code outside of that class, but in the same module.
>
> The constraint could, in theory, apply to other types such as struct or enum. But the suggestion currently relates to the class type only.
>
> The below example compiles just fine, as you would expect.
>
> // ------
> module test;
> @safe:
>
> class someClass
> {
>     private:
>         string _id;
>
>     public:
>         void setID(string id)
>         {
>             // some condition(s), if met, then:
>             _id = id;
>         }
> }
>
> unittest
> {
>     someClass myclass = new someClass();
>     myclass.setID("123");
> }
>
> // -----
>
> Is the above code consistent with the design intent of someClass?
>
> The answer must be yes, since in D, private is private to the module.
>
> But what if the intent was to require other code to 'use the inteface' to access x?
>
> The problem is, many coming to D, come from languages where you can already declare such an intent, and equally importantly, have that intent enforced by the compiler, at compile time.
>
> But the D programming language has no feature to declare such an intent. So where does this leave those programmers?
>
> The argument has been made, that D does not need such a feature, because scope is always at the module level.
>
> But it does not follow, that scope at the module level eliminates the need for such a feature. That argument is not logical.
>
> The next response, is that if you need this feature, then you can 'simulate it' by putting the class that needs this feature, into its own module.
>
> However, the one-class-per-module approach, imposes its own new design constraint, and not one the programmer necessarily makes of his/her own volition.
>
> It also does not necessarily follow, that a class in its own module, is there for the purposes of stipulating this constraint.
>
> There are any number of a reason, why a class might be put into its own module. You cannot infer anything from that. You'd have to speak the designer to know intent.
>
> Other arguments have also been made against adding such a feature, but it is difficult to take them seriously - such as 'why would a class ever need to hide something'.
>
> Now the advantage of adding such a feature, is that it provides private at the scope level for those who want or expect such a feature, it provides evidence of the designers intent to separate implementations from interface, and the compiler which now knows the intent, can enforce that intent, at compile time.
>
> So the only logical outcome of this discussion, is whether the benefit of adding a design constraint *option* to the language, outweighs the cost of adding it to the langauge.
>
> The benefits of adding this feature appear to be self-evident.
>
> So ultimately, this comes down to a benefit-vs-cost consideration.
>
> The cost of adding it to the language, is less self-evident.
>
> Is the cost, the unjustified cognitive burden of having both 'private' and 'private(scope)', instead of just 'private'?
>
> Is the cost - it's just too complicated to change the compiler source to accomodate this option?
>
> What do you think the cost of adding such a feature is?

I just want to +1 this. Even if I had to use a compiler switch.

'private' exists in many languages and has survived the test of time. Just because you don't use it doesn't mean other people don't--especially with D's bias toward gigantic 3000+ line module files. And if you don't like it, I don't see why you'd be suffering when it's an opt-in feature and you can just not use it.

I find that private makes for a great way for rapid incremental development (that D is great at). You get things working, then "private" them, and immediately all references to that variable, function, or "hidden thing" are now visible as compiler errors that you can go down the line and fix. It's not "opt in" (the way error correction is supposed to be--opt-out so you cannot accidentally miss it). There's no possibility of human error in the list. If you make an outside reference illegal, it's now visible to the compiler and you. You can private members and fields, as often or rarely as you want. One at a time, clean up some references, then another one.

The "alternative" is either do some gymnastics with entire classes moving around files to poorly emulate private, or, rename your interface variable/method in question which highlights all references to it as an error. Except that also includes CORRECT references in the list!

You don't want to use it in the standard library, go ahead. But that doesn't make it not useful. By that logic, I guess we should rip out BetterC.
June 14, 2022

On Tuesday, 14 June 2022 at 13:35:13 UTC, Ola Fosheim Grøstad wrote:

>

On Tuesday, 14 June 2022 at 13:06:02 UTC, Mike Parker wrote:
this, should it not prevent shadowing of public members?

I'd say it should, and i'd call this a bug. it should either require an override specifier, or the call side to be explicit

June 14, 2022

On Tuesday, 14 June 2022 at 13:35:13 UTC, Ola Fosheim Grøstad wrote:

>

You end up with the same issues. If D was principled about this, should it not prevent shadowing of public members?

Yes, it should, actually.

June 14, 2022
On Tuesday, 14 June 2022 at 13:55:57 UTC, Chris Katko wrote:
> On Tuesday, 14 June 2022 at 05:43:49 UTC, forkit wrote:
>> [...]
>
> I just want to +1 this. Even if I had to use a compiler switch.
>
> 'private' exists in many languages and has survived the test of time. Just because you don't use it doesn't mean other people don't--especially with D's bias toward gigantic 3000+ line module files. And if you don't like it, I don't see why you'd be suffering when it's an opt-in feature and you can just not use it.
>
> [...]

you can do that already too. move the class to it's own module and mark members as public.
then one at a time, turn them into private one by one. and you'll end up with the class in it's own module, where it actually belongs.
June 14, 2022

On Tuesday, 14 June 2022 at 12:35:24 UTC, bauss wrote:

>

On Tuesday, 14 June 2022 at 12:19:40 UTC, Mike Parker wrote:

>

On Tuesday, 14 June 2022 at 10:50:56 UTC, bauss wrote:

>

No you really can't and I already proved that with a couple examples in the other discussions on this topic; there are situations where you cannot do that, such as accessing private fields on a parent class using a sub class type within the parent class' module.

And Paul did show you how to do that with child.Foo._c.

Not in a legal way.

It is literally part of the language spec, how is it illegal?????

>

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


class A { int a; int a2;}
class B : A { int a; }

void foo(B b)
{
    b.a = 3;   // accesses field B.a
    b.a2 = 4;  // accesses field A.a2
    b.A.a = 5; // accesses field A.a
}