May 15, 2018
> (and don't tell me it does - cause the code below clearly demonstrates that it does not)
>
> =======
> module test;
>
> void foo()
> {
>     Person p = new Person("King Joffrey");
>
>     // this completely bypasses my interface
>     // (i.e. the boundary that I set up between the class and the module)
>     p._name = "New King";
>
> }
>
> class Person
> {
>     private string _name;
>
>     public void setName(string name)
>     {
>         this._name = name;
>     }
>
>     public this(string name)
>     {
>         _name = name;
>     }
>
> }
>
> ================================

Jonathan's right. We're just not going to agree on this. The implementation is still encapsulated behind the public interface. If you don't want main to access Person's private members, then don't put them in the same module. Period.

Modules are a cohesive unit, not simply a means of grouping related constructs. If the latter is all you're using them for, then the solution is simple. Given the following:

module foo.bar.baz;

class A {}
class B {}
class C {}
void funca() {}
void funcb() {}

You can keep your grouping and get your strict encapsulation like so:

// foo/bar/baz/package.d
module foo.bar.baz;
public import
    foo.bar.baz.a,
    foo.bar.baz.b,
    foo.bar.baz.c,
    foo.bar.baz.funcs;

The client need neither know nor care that everything is in separate modules and you get your strict encapsulation. You can still share items between modules via package protection, and within specific package hierarchies via package(packageName). And even better, you now have less code per module to reason about (re: one of your earlier arguments against the current behavior).
May 15, 2018
On Tuesday, 15 May 2018 at 05:59:44 UTC, Mike Parker wrote:
>
> Jonathan's right. We're just not going to agree on this.

The purpose of discussion is not necessarly to get one side to agree with other side.

> You can keep your grouping and get your strict encapsulation like so:
>
> // foo/bar/baz/package.d
> module foo.bar.baz;
> public import
>     foo.bar.baz.a,
>     foo.bar.baz.b,
>     foo.bar.baz.c,
>     foo.bar.baz.funcs;
>
> The client need neither know nor care that everything is in separate modules and you get your strict encapsulation. You can still share items between modules via package protection, and within specific package hierarchies via package(packageName). And even better, you now have less code per module to reason about (re: one of your earlier arguments against the current behavior).

Fine. If I take your solution above, and ensure that every class, goes into it's own module, and that a module containing a class, contains nothing other than a single class (i.e no free functions), then sure, I end up where I am now, with C++/Java/C# - i.e a good place, where I feel comfortable. My declared interface is respected.

Why do I need D then? i.e. under what circumstances, would I want to put something extra into the module, so that it can abuse the declared interface of my class?

Can you give me some examples?

May 15, 2018
On Tuesday, 15 May 2018 at 06:38:04 UTC, KingJoffrey wrote:
> Can you give me some examples?

Defining a Voldemort type (meaning, one whose name is not public) with private members for use by multiple functions:

-------
module two_functions;

private struct MyForwardRange
{   private int function(int[]) cumulator;
    int[] front;
    void popFront()
    {   front ~= cumulator(front);
    }
    enum empty = false;
    auto save()
    {   return this;
    }
}

auto accumulate(int a, int b)
{   import std.algorithm;
    return MyForwardRange(arr => arr.sum, [a, b]);
}

auto extendByIota(int[] startElems)
{   return MyForwardRange(arr => arr.length, startElems);
}
-------

In a simple module like this, it would be needless complexity to make cumulator have a package visibility and put the functions in a different module. That's what you would have to do if private meant private to class, not to module.
May 15, 2018
On Tuesday, May 15, 2018 06:38:04 KingJoffrey via Digitalmars-d wrote:
> On Tuesday, 15 May 2018 at 05:59:44 UTC, Mike Parker wrote:
> > You can keep your grouping and get your strict encapsulation like so:
> >
> > // foo/bar/baz/package.d
> > module foo.bar.baz;
> > public import
> >
> >     foo.bar.baz.a,
> >     foo.bar.baz.b,
> >     foo.bar.baz.c,
> >     foo.bar.baz.funcs;
> >
> > The client need neither know nor care that everything is in separate modules and you get your strict encapsulation. You can still share items between modules via package protection, and within specific package hierarchies via package(packageName). And even better, you now have less code per module to reason about (re: one of your earlier arguments against the current behavior).
>
> Fine. If I take your solution above, and ensure that every class, goes into it's own module, and that a module containing a class, contains nothing other than a single class (i.e no free functions), then sure, I end up where I am now, with C++/Java/C# - i.e a good place, where I feel comfortable. My declared interface is respected.
>
> Why do I need D then?

I honestly don't see how D deals with private should be a major factor in deciding what language to use. Even if you see how D handles private to be negative, if its other features aren't appealing enough to make you want to use it in spite of what's going on with private, I don't see why what happens with private matters. And even if private worked the way you want it to, I don't see why that would make anyone want to use the language over C++ or Java or whatnot. How stuff like private, package, and friends are dealt with certainly has an impact on a language, but it's just one piece of many, and I would expect most people to think that it was a relatively small piece of the puzzle such that it would not be a major deciding factor in whether they use the language, whether they like what was done with access levels or not.

> i.e. under what circumstances, would I want
> to put something extra into the module, so that it can abuse the
> declared interface of my class?

The declared interface to your class is what's presented to everything outside of your module. Everything inside the module has full access just like any friend would in C++. That's basically how you have to think about it. As long as you insist that the class itself is the barrier, then you're never going to be anything but unhappy with D's approach.

> Can you give me some examples?

The prime one is unit tests. The fact that they can access the private variables is invaluable for testing the state of an object. In C++, I have always have to make all of the tests friends of the class so that they can access the internals for testing. In D, I don't have to worry about any of that, and the tests don't affect the public interface of the class at all.

Also, there are plenty of cases where it's nice to be able to have private functions which can access the internals of a class - and you don't necessarily want them to be members of the class. This is particularly true when the class is templated. e.g. dxml provides a fairly simply public API in dxml.parser, but it has lots of private helper functions which access the members of the struct. They operate on stuff that isn't supposed to be publicly available, and it's cleaner to have them outside the struct where they can be tested separately from the struct.

Also, why would I necessarily care if something else in the same module can access the private members of a struct or class? If they're associated closely enough to be put in the same module, then there's frequently no reason to care if they access the private members or not, and as long as you're dealing with stuff like getters and setters, unless they're doing extra work other than simply encapsulating access to a member variable, there really isn't a reason why it would be a problem for other stuff in the module to access the member variable directly. Everything in the module goes together, and you can easily change anything in there if you need to due to something changing in the internals of the struct or class, and it won't affect the public API. Everything in the module is internal.

Particularly when you're talking about private functions, whether something is in the class itself or in the module is an implementation detail and largely irrelevant. And if you have a public free function that can access the class' internals, well that function is associated with the class by being in the same module just like a friend function would be, and you get all of the benefits that you'd get with a friend function without having to explicitly declare everything as friends. So, all of the same reasoning as to why you'd want a friend function applies to why it can be valuable to have something in the same module access the internals of a class. The only cost is that you can't declare something not to be a friend and have it be in the same module, and you can't declare it to be a friend when it's in another module (though package does provide similar functionality). The assumption is that anything that goes in the same module can either reasonably be treated as friends, or it doesn't matter if they are.

Basically all of the same arguments that you're giving against having everything in the module being treated as friends of each other can be given against having friends in the first place. It's just that D makes it implicit within the module.

- Jonathan M Davis

May 15, 2018
On Tuesday, 15 May 2018 at 07:23:55 UTC, Jonathan M Davis wrote:
>
> The prime one is unit tests. The fact that they can access the private variables is invaluable for testing the state of an object. In C++, I have always have to make all of the tests friends of the class so that they can access the internals for testing. In D, I don't have to worry about any of that, and the tests don't affect the public interface of the class at all.

ok. so the 'for' side arguments, for embracing Facebook style friendship in D:

- Voldemort types (cause yeah...we all use them so often).
- Unit tests (dare I the same ;-)

Actually, I kinda get it for unit tests.

Surely there's more??


> The assumption is that anything that goes in the same module can either reasonably be treated as friends, or it doesn't matter if they are.

Well, we already know what disasters can occur from facebook style friendships.

My own code in D had bugs, cause I didn't realise all my private parts were not just visible, but accessible by all the so called 'friends' around me. They could reach in a do whatever they want! Without my consent!

And btw, people grabbing your private parts without your explicit consent, is a really serious matter! Just ask those in the me-too movement.

Why should a programmers code be exempt from such considerations?

> Basically all of the same arguments that you're giving against having everything in the module being treated as friends of each other can be given against having friends in the first place. It's just that D makes it implicit within the module.
>

No. In C++, you only declare friends as part of your defined interface.

That's kind different to 'everyone around you is your friend. so you need to deal with it'.

They are not the same thing, and have to be approached differently.

May 15, 2018
On Tuesday, 15 May 2018 at 10:19:58 UTC, KingJoffrey wrote:
>
> - Voldemort types (cause yeah...we all use them so often).


Actually yes. Most people who has been writing D for a long time uses them.
May 15, 2018
On Tuesday, 15 May 2018 at 04:46:18 UTC, Jonathan M Davis wrote:
> On Tuesday, May 15, 2018 04:22:30 Mike Parker via Digitalmars-d wrote:
>> On Tuesday, 15 May 2018 at 02:32:05 UTC, KingJoffrey wrote:
>> > - Object independence
>> > - Do not violate encapsulation
>> > - Respect the interface
>>
>> This is what I don't get from your position. What is encapsulation? Here's what Wikipedia says [1]:
[...]
>>
>> The class in D *is* encapsulated. The interface *is* respected. I'm not sure what you mean by object independence.
>>
>>
>> [1]
>> https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)
>
> If you really insist on the viewpoint that class encapsulation means that nothing outside of that class can access any of its private members, then what D does definitely breaks encapsulation. But having friends in C++ already provides a way to break that. And having access levels like protected and package break it. Ultimately, a good language provides ways to encapsulate data and control access to the internals of a data type, but there are a variety of ways that that can be achieved, and I don't think that I've ever used a language that strictly enforces that nothing can access the internals of a class. It's just that each language provides different ways for stuff outside the class to access the class' internals.
>
> D happens to have gone with a very liberal approach to encapsulation by essentially making everything inside a module friends of each other. It doesn't break the concept of encapsulation any more than C++'s friend or Java's package attribute do. It's just a much more liberal default, and if you're really insistent that nothing outside of a class has access to the stuff inside a class, then D's choice is likely to be seem terrible. So, in that sense, I can see where he's coming from, but ultimately, I think that it's a very narrow viewpoint about what encapsulation means, and for most of us, experience has shown that D's choice works extremely well in practice.
>
> Either way, as long as you understand how D works with private, you have basically the same level of control as what you get with C++ and friend. It's just that if you _really_ don't want anything else to be a friend, you're forced to stick it in another module. So, ultimately, I think that it's mostly a theoretical debate. Pretty much the worst that happens is you accidentally use a member variable directly instead of using a property function to access it, and that's rarely a big deal. Often, it's even desirable.
>
[...]
>
> - Jonathan M Davis

With one big difference, in that those other languages make you explicitly leak object internals, if you want it, and also allow you to maintain it, if you want it, whereas D implicitly leaks class privates to the module whether you want it or not. So private in a class is nonintuitive and does indeed break encapsulation. This is why Swift has fileprivate to distinguish this case, and for good reason.

So I understand D wants to be liberal, but I also understand the value of "encapsulation where I want encapsulation to happen", which D doesn't let me do without jumping through extra hoops (extracting class to another module with the caveat that you lose first-class UFCS enabled function access), and only after I've spent hours trying to track a state-related bug because private is not scoped at the declaration level.

Cheers
- Ali

May 15, 2018
On Friday, 11 May 2018 at 10:32:39 UTC, KingJoffrey wrote:
> On Friday, 11 May 2018 at 09:47:39 UTC, Dukc wrote:
>> You can use D private with Java-like "only for members functions" meaning by putting it alone in it's module, if you want.
>
> Yes. I do know this. But that is essentially.. a hack.

Funny that you call this a hack, see below.

> A 'private' declaration should be part of the implementation of the class, not the class+module. Some say this is just a philosphical difference - I say it's a key design issue for structured programming.

(OT: "structured programming" is generally understood as a concept introduced by the Pascal programming language, and has nothing to do with OOP. You probably use the term in a broader sense here though, and that's OK.)

[...]

> So now, in D, to understand the class, you must also understand the module.

Yes.

> This is a backwards step in language design, in my opinion - for various reasons which are easy to examine further.

Sometimes it is good to do a step back, if thereby you correct steps taken in the wrong direction. I have been watching video's of Robert Martin lately, a.k.a. Uncle Bob. His experience is far greater than mine, and his view on encapsulation is pretty clear. Here are a few of his quotes, made in for example [1]:

  "We had absolutely perfect encapsulation in C."
  "This all got screwed up by C++."
  "In C++, header files got polluted with variables and we lost encapsulation. To fix that, we did this really horrible hack: we invented the word 'private'."
  "'private:' is a terrible hack which attempts to recapture at least some tiny bit of the lost encapsulation that we had in C."
  "Then [...] we invented the word 'protected' and ever since then we have been figuring out other ways to open that up so now we've got 'package scope' and this cope and that scope and God help us all there's no encapsulation left."
  "OO has ruined encapsulation."

I am not suggesting that everybody should accept that view, but defining modules as the unit of encapsulation cleans up a lot of the mess -- at the cost of having to design a sensible module hierarchy. Encapsulation predates OO and it is not something that can only be had with OO. D puts encapsulation back where it used to be and where it works well: decoupled from OO so that the public interface can be designed independently from inheritance and polymorphism.

[1] https://www.youtube.com/watch?v=t86v3N4OshQ&t=20m4s
May 15, 2018
On Tuesday, 15 May 2018 at 12:20:34 UTC, aliak wrote:
> On Tuesday, 15 May 2018 at 04:46:18 UTC, Jonathan M Davis wrote:
>> On Tuesday, May 15, 2018 04:22:30 Mike Parker via Digitalmars-d wrote:
>>> On Tuesday, 15 May 2018 at 02:32:05 UTC, KingJoffrey wrote:
>>> > - Object independence
>>> > - Do not violate encapsulation
>>> > - Respect the interface
>>>
>>> This is what I don't get from your position. What is encapsulation? Here's what Wikipedia says [1]:
> [...]
>>>
>>> The class in D *is* encapsulated. The interface *is* respected. I'm not sure what you mean by object independence.
>>>
>>>
>>> [1]
>>> https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)
>>
>> If you really insist on the viewpoint that class encapsulation means that nothing outside of that class can access any of its private members, then what D does definitely breaks encapsulation. But having friends in C++ already provides a way to break that. And having access levels like protected and package break it. Ultimately, a good language provides ways to encapsulate data and control access to the internals of a data type, but there are a variety of ways that that can be achieved, and I don't think that I've ever used a language that strictly enforces that nothing can access the internals of a class. It's just that each language provides different ways for stuff outside the class to access the class' internals.
>>
>> D happens to have gone with a very liberal approach to encapsulation by essentially making everything inside a module friends of each other. It doesn't break the concept of encapsulation any more than C++'s friend or Java's package attribute do. It's just a much more liberal default, and if you're really insistent that nothing outside of a class has access to the stuff inside a class, then D's choice is likely to be seem terrible. So, in that sense, I can see where he's coming from, but ultimately, I think that it's a very narrow viewpoint about what encapsulation means, and for most of us, experience has shown that D's choice works extremely well in practice.
>>
>> Either way, as long as you understand how D works with private, you have basically the same level of control as what you get with C++ and friend. It's just that if you _really_ don't want anything else to be a friend, you're forced to stick it in another module. So, ultimately, I think that it's mostly a theoretical debate. Pretty much the worst that happens is you accidentally use a member variable directly instead of using a property function to access it, and that's rarely a big deal. Often, it's even desirable.
>>
> [...]
>>
>> - Jonathan M Davis
>
> With one big difference, in that those other languages make you explicitly leak object internals, if you want it, and also allow you to maintain it, if you want it, whereas D implicitly leaks class privates to the module whether you want it or not. So private in a class is nonintuitive and does indeed break encapsulation. This is why Swift has fileprivate to distinguish this case, and for good reason.
>
> So I understand D wants to be liberal, but I also understand the value of "encapsulation where I want encapsulation to happen", which D doesn't let me do without jumping through extra hoops (extracting class to another module with the caveat that you lose first-class UFCS enabled function access), and only after I've spent hours trying to track a state-related bug because private is not scoped at the declaration level.
>
> Cheers
> - Ali

The way you use the word "leak" make is sounds that this is unintentional, while in reality it is intentional by design. That why reading the specification is important!

Alexander

May 15, 2018
On Tuesday, 15 May 2018 at 10:19:58 UTC, KingJoffrey wrote:

> Actually, I kinda get it for unit tests.
>
> Surely there's more??

I use it all the time. One way is to replace what would have been a "Manager" class in Java or elsewhere.

module foo.window;
class Window {
    private WindowHandle _handle;
    private void close() {}
}

private Window[WindowHandle] _windows;
package void closeWindow(Window window) {
    _windows.remove(window._handle);
    _window.close();
}

This is exactly how I reason about the code and is similar to how I would have structured it in C, but with the benefit of both package- and module-level encapsulation. _windows, window._handle, and window.close are hidden from both the outside world and the package.

I can't see any possible reason why I would want to hide the implementation of Window from closeWindow -- they're in the same module! It's not like C++, where multiple classes can belong to multiple namespaces in the same source file. Everything in window.d is in the same namespace.

>
> And btw, people grabbing your private parts without your explicit consent, is a really serious matter! Just ask those in the me-too movement.
>
> Why should a programmers code be exempt from such considerations?

D doesn't make that exemption. No one from outside the module has access to your private parts. If you have access to the class, you also have access to the module, and everything is in the same namespace by design, so you're grabbing your own private parts. Why should programmers be prevented from doing that?