May 12, 2018
H. S. Teoh wrote:

p.s. and struct with `alias this` will allow us to extend it with fields too. not without using some other tricks, of course, but as there is a documented and ligitimate way to workaround any "sealing", i myself see a little sense in such feature. the only thing it will be good at is annoying users, who will be forced to write workarounds.
May 12, 2018
On Friday, 11 May 2018 at 19:45:10 UTC, rumbu wrote:

>
> The first example is unit testing. Having access to the private members of a class inside the same module is a mistake because it breaks the idea of encapsulation. Unit testing must be done exclusively on public members of a class. If you are feeling the urge to test a class private thing, there is something wrong with your class design. In the parallel world of true OOP which D tries to avoid as much as possible there is a saying for that: "Everytime you test a private method, a unicorn dies".

My point is that it *doesn't* break encapsulation. The *module* is the lowest level of encapsulation, not the class. The public API is not affected by any changes internal to the module. And, like Jonathan, I disagree with the assertion that private members shouldn't be tested.

>
> The second example is inter-class access of private members if you have multiple classes in the same module. The "define a class per module" is not a solution in this case because D lacks the idea of namespace an it's just ridiculous to have a library with 1000 different modules just to achieve real class encapsulation.

Again, they're in the same module. From an encapsulation stand point, what does it matter that private members are within or without any specific set of curly braces? It only matters if you want to adhere to a purely conceptual view of encapsulation. From a practical view, it matters not one whit.

>
> The third example is pollution of IDE code completion in the same module with members which are not meant to be there.

If they're in the same module, then they're meant to be there.
May 12, 2018
On Saturday, 12 May 2018 at 00:39:29 UTC, Mike Parker wrote:
>
> Again, they're in the same module. From an encapsulation stand point, what does it matter that private members are within or without any specific set of curly braces? It only matters if you want to adhere to a purely conceptual view of encapsulation. From a practical view, it matters not one whit.
>
>>

It matters, in the same sense, that it matters if you have a module, full of functions (which are encapsulated units of code), but your module has a whole bunch of goto statements (not necessarily within a function). Now...you've essentially no idea now which functions are truly encapsulated, and which aren't. You now have to take into view, 'the whole module' - which goes against the very principle of problem solving by breaking down the problem into smaller pieces.

I have looked a D source code modules. I challenge anyone to get there head around whole modules.

In a similar vain to gotos, having classes (which are traditionally meant to be encapsulated units of code) in a module, but also having anything in the module (outside of the class[es]), having the capacity to do whatever it wants to the private parts of the class.

We're back in goto land!



May 12, 2018
On Friday, 11 May 2018 at 19:30:51 UTC, bauss wrote:
> It's a problem to you, but not to me and I'm sure many others in the D community can agree that private being module level has a lot of benefits over private being "class-level".

These are the benefit I can see:

- it encourages more complex, ill-structured problem solving skills.

- it increases cognitive load on those seeking to understand the solution (cause now they have to take into accont the 'entire' module, as opposed to smaller encapsulated units of code within the module.)

We're back in goto land!

May 12, 2018
On 12/05/2018 3:02 PM, KingJoffrey wrote:
> On Saturday, 12 May 2018 at 00:39:29 UTC, Mike Parker wrote:
>>
>> Again, they're in the same module. From an encapsulation stand point, what does it matter that private members are within or without any specific set of curly braces? It only matters if you want to adhere to a purely conceptual view of encapsulation. From a practical view, it matters not one whit.
>>
>>>
> 
> It matters, in the same sense, that it matters if you have a module, full of functions (which are encapsulated units of code), but your module has a whole bunch of goto statements (not necessarily within a function). Now...you've essentially no idea now which functions are truly encapsulated, and which aren't. You now have to take into view, 'the whole module' - which goes against the very principle of problem solving by breaking down the problem into smaller pieces.
> 
> I have looked a D source code modules. I challenge anyone to get there head around whole modules.

Its actually pretty easy.
I have yet to find a D module I couldn't understand.

Now IntelliJ IDEA on the other hand...
I gave up on my recent iteration of a plugin for D when discovering I really did not understand how its setup enough to add something to the configuration dialog. Let alone SDK and what not.


May 12, 2018
On Friday, 11 May 2018 at 14:05:25 UTC, KingJoffrey wrote:
> private is not private at all in D, and because of this, classes are fundamentally broken in D (by design apparently).

I find this amusing because D does things exactly like Java. In Java, two sibling nested classes can call private functions on each other. But nobody says that this makes Java's classes fundamentally broken.

Like, this just works in Java:

public class Protections {
    public static class Bar {
        private void bar() { System.out.println("bar"); }
    }

    public static class Baz {
        private void bar(Bar b) { b.bar(); }
    }

    public static void main(String[] args) {
        new Baz().bar(new Bar());
    }
}

A function calling a private method defined in a different class, which calls a private function defined in yet another class! Utter madness! But the sky hasn't fallen, even though there's probably a thousand times as much Java code written as D.
May 12, 2018
On Friday, 11 May 2018 at 23:28:48 UTC, Jonathan M Davis wrote:
> Except that if I understand correctly, what the OP wants is to have the class be publicly available while restricting who's allowed to derive from it, with the idea that a particular class hierarchy would have a well-defined set of classes that the person who wrote them had full control over rather than allowing anyone and everyone to derive from any class in the hierarchy except for any final classes at the leaves of the hierarchy.

Exactly that is the point.

I'll give you an example from an app I've started working on:

I developed a little CQRS library. The structure of classes is based on the Entity type - an entity is a piece of data that is sent between a client and a server. Client/server that has received the entity, detects the right Handler class for the given entity class and triggers it. Handler for some entity types will generate other entities, which will be sent to their handlers respectively or sent back over the network to be handled remotely.

There are four types of entitites: Commands, Queries, Responses and Events.

The most typical patterns are:
- Client sends a command to the server. Server uses a CommandHandler to generate resulting Events and EventHandlers to take actions corresponding to them. Eventually it may acknowledge the client that the command has been successfully processed, but without any data in response.
- Client sends a Query. The server processes it in QueryHandler, which generates a Response that is sent back. Client uses its ResponseHandler to take actions corresponding to the response, such as presenting the results in the UI.

Class-wise, we have:
- abstract class Entity,
- abstract classes Command, Event, Query and Response, each of them extends Entity,
- a number of concrete classes being the particular Commands, Events, Queries and Responses.

Now what I want to achieve is prevent library user to extend the Entity class. There are four classes inheriting the Entity class and the entire concept is built around these four. Library's internal code is also constructed to support only these four entity types, which make the concept complete and non-extendable by design. Currently user is able to create a fifth type of Entity, but the library will not - and is not meant to - support it in any other way then throwing an exception.

If I made the Entity class private as Walter suggested, I could not create a method to transfer any entity type via network or couldn't create for example a log method that accepts Entity as a parameter (Yes, there is a Variant and Algebraic, but I don't think that it is the right use for them). What I want to have is an entity class visible everywhere, but extendable only inside my library. At the same time I want users to be able to freely extend the Command, Event, Query and Response classes, as this is exactly what the concept is about.
May 12, 2018
On Saturday, 12 May 2018 at 04:29:32 UTC, Neia Neutuladh wrote:
> On Friday, 11 May 2018 at 14:05:25 UTC, KingJoffrey wrote:
>> private is not private at all in D, and because of this, classes are fundamentally broken in D (by design apparently).
>
> I find this amusing because D does things exactly like Java. In Java, two sibling nested classes can call private functions on each other. But nobody says that this makes Java's classes fundamentally broken.
>
> Like, this just works in Java:
>
> public class Protections {
>     public static class Bar {
>         private void bar() { System.out.println("bar"); }
>     }
>
>     public static class Baz {
>         private void bar(Bar b) { b.bar(); }
>     }
>
>     public static void main(String[] args) {
>         new Baz().bar(new Bar());
>     }
> }
>

Come on, your code example misses my point completely.

Take this program below, for example, and tell me that class encapsulation is not broken in D:

===============================
module test;

import std.stdio : writeln;

void main()
{
    Person p = new Person("King Joffrey");

    writeln(p.getName); // I designed my class to return this.
    writeln(p._name); // But D can bypass your intention completely.

    p._name = "New King"; // even worse, D can nominate another king.
    writeln(p._name);
}

class Person
{
    private string _name;

    public void setName(string name)
    {
        this._name = name;
    }

    public string getName()
    {
        return ProperName(this._name);
    }

    public this(string name)
    {
        _name = name;
    }

    private static string ProperName(string name)
    {
        return name ~ " : The one true king!";
    }
}

==============================
May 12, 2018
On 12/05/2018 6:35 PM, KingJoffrey wrote:
> On Saturday, 12 May 2018 at 04:29:32 UTC, Neia Neutuladh wrote:
>> On Friday, 11 May 2018 at 14:05:25 UTC, KingJoffrey wrote:
>>> private is not private at all in D, and because of this, classes are fundamentally broken in D (by design apparently).
>>
>> I find this amusing because D does things exactly like Java. In Java, two sibling nested classes can call private functions on each other. But nobody says that this makes Java's classes fundamentally broken.
>>
>> Like, this just works in Java:
>>
>> public class Protections {
>>     public static class Bar {
>>         private void bar() { System.out.println("bar"); }
>>     }
>>
>>     public static class Baz {
>>         private void bar(Bar b) { b.bar(); }
>>     }
>>
>>     public static void main(String[] args) {
>>         new Baz().bar(new Bar());
>>     }
>> }
>>
> 
> Come on, your code example misses my point completely.
> 
> Take this program below, for example, and tell me that class encapsulation is not broken in D:
> 
> ===============================
> module test;
> 
> import std.stdio : writeln;
> 
> void main()
> {
>      Person p = new Person("King Joffrey");
> 
>      writeln(p.getName); // I designed my class to return this.
>      writeln(p._name); // But D can bypass your intention completely.
> 
>      p._name = "New King"; // even worse, D can nominate another king.
>      writeln(p._name);
> }
> 
> class Person
> {
>      private string _name;
> 
>      public void setName(string name)
>      {
>          this._name = name;
>      }
> 
>      public string getName()
>      {
>          return ProperName(this._name);
>      }
> 
>      public this(string name)
>      {
>          _name = name;
>      }
> 
>      private static string ProperName(string name)
>      {
>          return name ~ " : The one true king!";
>      }
> }
> 
> ==============================

Now move Person into its own module.
Boom errors.

This is how module systems should work and everything is working correctly :)

You will not convince us otherwise.
May 12, 2018
On Friday, 11 May 2018 at 20:22:52 UTC, H. S. Teoh wrote:
> On Fri, May 11, 2018 at 02:04:34PM -0600, Jonathan M Davis via Digitalmars-d wrote:
>> On Friday, May 11, 2018 19:45:10 rumbu via Digitalmars-d wrote:
> [...]
>> > The first example is unit testing. Having access to the private members of a class inside the same module is a mistake because it breaks the idea of encapsulation. Unit testing must be done exclusively on public members of a class. If you are feeling the urge to test a class private thing, there is something wrong with your class design. In the parallel world of true OOP which D tries to avoid as much as possible there is a saying for that: "Everytime you test a private method, a unicorn dies".
>> 
>> I completely disagree with this. Testing private functions can be extremely valuable for ensuring that everything within the type functions the way that it should and can often lead to much better testing of how pieces of a type work, because you have better control over what's going on at that exact point in the call chain when you're testing it directly.
>
> Yeah, in my own projects I have found that unittesting private functions has been a life-saver in catching bugs early (especially if you're writing a complex class / struct / type / module with many moving parts), ensuring helper functions actually work, and also building confidence that the code is actually doing what you think it's doing. Testing only the external API means I have to write a ton of code before a single test can be run, which means a lot more places for bugs to hide and a lot more time wasted trying to locate a bug buried deep within several levels of function calls under the public API.
>
> If it's true that a unicorn dies everytime I test a private method, then I say, kill 'em all off, they deserve to go extinct!
>
> (None of this negates the fact that public APIs need to be thoroughly tested, of course.  Like Jonathan, I just don't see how one could argue that private methods should *not* be tested.)
>
>
> T

I never said that. Feel free to test your private methods as long as you want it if you think that will improve your code correctness. But for *me* this is a bad practice. Every time I am in a situation that will result in such need, I question myself if there is something wrong with my class design and usually I end with extracting that private functionality to another class that can be tested.

Testing private functionality means that you *lock* the internal implementation of your class. If you decide later to change the implementation, your previous tests will have zero-value.

On the contrary, testing public functionality of a class will *lock* the design and this is desirable at least from a library design point of view.

The difference here is that D is offering you the means to code your stuff exactly as you want it, but the same is not true for my way of coding. And this is really annoying when you are doing TDD where the public testing of a class is in fact the definition of functionality and I don't want to touch by mistake any private member in the process.

class SquareRoot
{
  private void someComplicatedAlgorithm { ... }
  public void calculate() { ... someComplicatedAlgorithm() ... }
}

unittest
{
  //assert something about someComplicatedAlgorithm....
  //and so on.
}


Let's suppose that one day I will change someComplicatedAlgorithm and most of the assertions will not be satisfied. That moment I have two options: modify all my assertions to match or completely delete them, hence the zero-value of them.

It will not be better to limit my assertions to calculate() instead?