October 28, 2018
On Saturday, 27 October 2018 at 03:20:43 UTC, Mike Parker wrote:
> On Friday, 26 October 2018 at 22:01:42 UTC, 12345swordy wrote:
>> On Friday, 26 October 2018 at 21:46:27 UTC, Laurent Tréguier wrote:
>
>>> You simply seemed to be implying that private had the same effect as protected, which isn't the case.
>> ... How can I make my self any more clear here!? When I say y behaves like x it I don't means y is exactly the x! Nor does it imply that!
>
> Here's the example code from your issue #19334:
>
> ```
> import std.stdio;
> class A
> {
>     private int y;
> }
>
> class B : A
> {
> };
>
> void main()
> {
>     B b = new B();
>     b.y = 1; // Should be a compile error as class shouldn't have private int y.
>     writeln(b.y);
> }
> ```
>
> First, this really is about encapsulation and *not* inheritance. Even if class B is in another module, it would still inherit y, i.e. it would have its own copy of y. private working as intended.
>
> Second, A, B, and main are in the same module. The spec clearly says that everything in the same module has access to private members. I quoted it in the bug report and it's been quoted two or three times here. So main has access to y.
>
> If used to be that even if you moved the declaration of B to another module, then main would still have access to y through b. That was deemed to be a bug an is now deprecated. But as long as they are all in the same module, it's working as intended.
Oh for the record, I had realized that I had embarrassed myself greatly with my own stupidity. Sorry.

Alex

October 29, 2018
On Sun, Oct 28, 2018 at 9:30 PM unprotected-entity via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Sunday, 28 October 2018 at 05:28:31 UTC, Mike Parker wrote:
> >
> > You can make the same mistake inside the class:
> >
> > class Foo {
> >    private int x;
> >    void increment() {...}
> >    ...
> >    void doSomethingInternal() { x++; }
> > }
> >
> > How is making that mistake outside of that final curly brace any different or any worse? It's all in the same file.
>
> Except, that (I assume) a module in D is meant to be more than
> just a single class.
>
> If that's not the case, then my argument is irrelevant.
>
> If it is the case, then you presumably would have a great deal
> more code in your module, than you would in a single class.
> Hence, greater likelihood of mistakingly
> accessing a private member of some class defined within the
> module, somewhere.
>
> In any case, it does undermine the principle of encapsulation (assuming you agree that a class deserves to be a unit of encapsulation).
>
> In, it's nothing more than a convenient hack, really.
>
> There is not a third option here.
>
> The advantage of the Way D does things is that you don't have to put your
data into a class and instantiate it in order to have encapsulation.
In C++ for instance often data is put into a class just to have
encapsulation, this has a cost in resources as well the complexity of
program.
In D any data that there only needs to be one copy of and lasts the
lifetime of the program belongs in a module rather than a class.
In practice this tends to mean less classes, and less of the work done
inside classes.
D source code can feel inside out compared to C++ source code.


October 29, 2018
On Sunday, 28 October 2018 at 11:32:07 UTC, Mike Parker wrote:
>
> In D, the module is the unit of encapsulation, not the class.

Again. this is not entirely correct.

-----
class Foo { private int i; }

void main()
{
 {Foo f;}
 f.i++;
}

----

It's really hard to have a converstation when posts are being checked by 'someone', at 'their leisure', before (or if) they ever get posted??


October 29, 2018
On Sunday, 28 October 2018 at 11:32:07 UTC, Mike Parker wrote:
>
> In D, the module is the unit of encapsulation, not the class.

That is not entirely correct.

---
module test;
import std.stdio;
void test() { int a; }
void main() { writeln(a); } // Error: undefined identifier 'a'
---

The D module still considers a function to be it's own unit of encapsulation.

Classes no longer have that status in D.

Now, for the small number of D users, it seems a relative non-issue. Fine.

I wonder if that would still be the case, if millions and millions of C++/Java/C# programmers suddenly came over to D (and discovered, likely by accident, or by some obscure bug in their code), that a class is not considered a unit of encapsulation anymore.

I think you would then have a much harder time convincing larger numbers of programmers, that D has done a good thing here (n terms of architecturing better software) by altering the most important encapsulating property of a class - private.

I'm guarantee, that you'd be getting a *lot* more DIP's that try to address it ;-)

I think Go and Rust have done it better, somewhat, in that they don't even have classes. So you are forced to rethink your design anyway (if you want to use those languages)

Having said that, I am yet to hear a really good argument, as for why everything in a module *must* be your friends. Encapsulation, is not about having lots of friends that can poke at your private parts - no matter what language it is.

But in a language that offers 'classes', but NOT as unit of encapsulation in its own right (within a module that is), well, I find that rather odd, and disconcerting (in terms of reasonable guarantees of your softwares correctness).

I understand that practical considerations are often more important, and useful, that theoretical standpoints, but even so, I do not see the wholesale practicality and usefulness of the decision made in D, in relation to this matter.

Yes, there are situations in which it might be useful, I get it. But surely not every situation?


October 29, 2018
On Monday, 29 October 2018 at 05:13:22 UTC, unprotected-entity wrote:

>
> Having said that, I am yet to hear a really good argument, as for why everything in a module *must* be your friends. Encapsulation, is not about having lots of friends that can poke at your private parts - no matter what language it is.
>

I've always understood encapsulation to be about the public API. I've generally seen two primary reasons given as to the purpose behind managing access: hiding complexity, and managing change.

For the first, consumers of an API need not know or care about the implementation details. Access modifiers allow the producers of an API to hide the details of the implementation and only expose what the consumer actually needs.

For the second, changes to the implementation of an API should ideally not impact the public API. Access modifiers allow the producer to segregate the changeable from the unchangeable.

From that perspective, D's system does not break encapsulation. From outside the module, publicly accessible symbols (including classes, structs, their members, and module-scope declarations) provide the public API for which change should be minimal. From inside the module, encapsulation is achieved with the package and private access modifiers.

In my opinion, you're making a purely abstract argument. Conceptually, the class is its own entity, true. But anyone who can edit the file in which the class resides can also edit the class implementation. Encapsulation inside the file is rather pointless.

I understand the argument about accidentally bypassing accessors to directly modify private members that shouldn't be modified. But the same thing can happen from inside the class. IIRC, one of the tips in Effective Java was to always use accessors to modify member variables even inside the class, and it's fairly common in Java to do so, to avoid causing subtle bugs like that. But the language doesn't require it, nor should it.

I see D's modules in the same light. There's no need to add more complexity to the language to solve a problem that is arguably rare in practice. If you're worried about accessing private members in a module, then use a naming convention that clearly marks private variables (I use an underscore in front, _foo) and never directly modify any variable with an underscore. If you're worried about other people doing it, split your modules and use the package access modifier to organize your package. The tools to solve this potential issue are there. We don't need more.

Anyway, I'm not the one who needs convincing. And I have a high degree of confidence that the ones who do need convincing won't be. There has yet to be a strong enough argument to change this behavior.

October 29, 2018
On Monday, 29 October 2018 at 00:36:43 UTC, Danni Coy wrote:
> On Sun, Oct 28, 2018 at 9:30 PM unprotected-entity via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
>
>> [...]
> data into a class and instantiate it in order to have encapsulation.
> In C++ for instance often data is put into a class just to have
> encapsulation, this has a cost in resources as well the complexity of
> program.
> In D any data that there only needs to be one copy of and lasts the
> lifetime of the program belongs in a module rather than a class.
> In practice this tends to mean less classes, and less of the work done
> inside classes.
> D source code can feel inside out compared to C++ source code.

No need for complicated singleton pattern in D.
October 29, 2018
On Monday, 29 October 2018 at 05:13:22 UTC, unprotected-entity wrote:
> On Sunday, 28 October 2018 at 11:32:07 UTC, Mike Parker wrote:
>>
>> In D, the module is the unit of encapsulation, not the class.
>
> That is not entirely correct.
>
> ---
> module test;
> import std.stdio;
> void test() { int a; }
> void main() { writeln(a); } // Error: undefined identifier 'a'
> ---
>
> The D module still considers a function to be it's own unit of encapsulation.
>
> Classes no longer have that status in D.
>
Yes they do.
---
module test;
import std.stdio;
class C { int a; }
void main() { writeln(a); } // Error: undefined identifier 'a'
October 29, 2018
On Monday, 29 October 2018 at 08:34:39 UTC, FeepingCreature wrote:
> Yes they do.
> ---
> module test;
> import std.stdio;
> class C { int a; }
> void main() { writeln(a); } // Error: undefined identifier 'a'

Sorry, but you are wrong.

Why? Because 'a' is nothing - it does not even exist. Not anywhere.

To make it exist, you need to instantiate an object of C.

Once it actually 'exists', you can do whatever you like with it, in the module, regardless of its access modifier. That means, quite simply, that the class is not a unit of encapsulation - within the module. Outside the module it is, but inside, it is not.

That is just fact. It's not something we should be arguing about - cause it's just a fact.

On the otherhand, a function (unlike a class) within a module, still retains it's encapsulating properties.

i.e.
void test() {int a;};
void main() {a++;}; // Error: undefined identifier 'a' - but this time, 'a' does exist - it's just that its correctly encapsulated in the function.


Just imagine if a function did not have those encapsulating properties.

Now, just imagine if a class did not (well, you don't need to imagine it ;-)

I'm not trying to argue here. I'm just trying to clarify a fact, that some seem unable, or unwilling, to accept.


October 29, 2018
On Monday, 29 October 2018 at 06:15:25 UTC, Mike Parker wrote:
> Encapsulation inside the file is rather pointless.

Say that to yourself a few times, and see if your view changes ;-)

(btw. just take a look at the length of some 'files', within Phobos - I mean, gee, I really hope the developer of those files did not share your view)

In any case, encapsulation in a file, still exists, just not so much for classes
- function still have it, scope braces still have it..etc..etc... but one of the most important constructs in programming, the class, does not.

> I understand the argument about accidentally bypassing accessors to directly modify private members that shouldn't be modified.

It's not just that it could happen 'by accident', it's that D actively encourages this, by making 'private' (within a module), a completely useless construct.

It's there by default.

Just how often does one need to access the private members of a class, within a module?

October 29, 2018
On Monday, 29 October 2018 at 06:15:25 UTC, Mike Parker wrote:
>
> Anyway, I'm not the one who needs convincing. And I have a high degree of confidence that the ones who do need convincing won't be. There has yet to be a strong enough argument to change this behavior.

If anything, someone should be trying to convince me, to use D ;-)

I do not believe, that a case can be made, to alter the status quo (if for no other reason, than to ensure existing code, keeps working).

Howver, I have seen, on many occassions now, where this issue has popped up, along with ideas on how to possibly solve it. On each occassion, the idea gets put to rest very quickly, by some, one way or another.

I think that is a real shame.

A way to make a class member private, within a module, is an idea worthy of consideration, and has immediate practical value, both in terms of convincing people to use D, and also in better guarantees around the correctness of your code.

The only argument for dismissing these ideas, when they pop up, seems to be, that nobody would ever be able to convince Walter/Andrei.. so why bother pursuing it any further.

They are the stewards of the language, I get it, but I think that's a sad state of affairs.

Inside a module, a private member of a class is a good, useful, practical construct (and I thought D was practical?).