May 12, 2018
On Saturday, 12 May 2018 at 06:38:16 UTC, rikki cattermole wrote:
>
> 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.

If D treated functions, like it treats classes, then you could do this in D (see below) - and the argument to get around the problems this causes, would be to put each individual function in it's own module.

That is in essence, your proposed solution to the problem with class encapsulation in D.

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

void main() { goto wtf; }

void foo()
{

wtf: return;

    return;
}
==========
May 12, 2018
On Saturday, May 12, 2018 06:42:24 rumbu via Digitalmars-d wrote:
> 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?

That's your choice, but even if you decided to refactor in a way that it made sense to throw away all of the tests for a private function, at least it was well-tested up to that point, and the tests had value as long as they made sense. Personally, I would _much_ rather be very thorough with my tests and then later have to seriously rework existing tests or throw them away when I refactor than to not have thorough testing. And my experience is that if a private function is anything other than really short and simple, having tests for it catches bugs and improves the quality of my code, regardless of whatever refactoring I may or may not do later.

You obviously don't have to test your private functions if you don't want to, but if you're trying to state that testing private functions is bad practice (and that's very much what it seemed like you were saying when you talked about testing private functions killing unicorns), then I'm very much going to disagree - especially in cases where the public API is relatively simple but does a lot of stuff underneath the hood.

- Jonathan M Davis

May 12, 2018
On 12/05/2018 7:07 PM, KingJoffrey wrote:
> On Saturday, 12 May 2018 at 06:38:16 UTC, rikki cattermole wrote:
>>
>> 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.
> 
> If D treated functions, like it treats classes, then you could do this in D (see below) - and the argument to get around the problems this causes, would be to put each individual function in it's own module.
> 
> That is in essence, your proposed solution to the problem with class encapsulation in D.
> 
> ============
> module test;
> 
> void main() { goto wtf; }
> 
> void foo()
> {
> 
> wtf: return;
> 
>      return;
> }
> ==========

I see no problem.

onlineapp.d(1): Error: label wtf is undefined
May 12, 2018
On Saturday, 12 May 2018 at 07:19:47 UTC, rikki cattermole wrote:
>
> I see no problem.
>
> onlineapp.d(1): Error: label wtf is undefined

The 'Error' is my point. It's not possible to do this - which is a good thing.

D protects the encapsulation unit of the function from such abuse.

But the same is not true for classes.

May 12, 2018
On Saturday, May 12, 2018 07:29:47 KingJoffrey via Digitalmars-d wrote:
> On Saturday, 12 May 2018 at 07:19:47 UTC, rikki cattermole wrote:
> > I see no problem.
> >
> > onlineapp.d(1): Error: label wtf is undefined
>
> The 'Error' is my point. It's not possible to do this - which is a good thing.
>
> D protects the encapsulation unit of the function from such abuse.
>
> But the same is not true for classes.

You could argue the same of friend functions in C++.

Yes, D weakens the encapsulation of classes in comparison to C++, but it simplifies the language in comparison to needing friend functions like C++ does, and it works _really_ well with stuff like unit testing. Other languages are forced to do stuff like have member functions and variables be protected just so that you can have a unit testing class access them via inheritance, whereas D avoids the need to change the class' API just to be able to test it, because the module has full access to it.

Ultimately, it's a tradeoff, and arguments can be made for and against. But in practice, it works extremely well. You're certainly free to not like this particular design choice, but it's one that most of us have no problem with, and I'd be shocked to ever see it change. So, you can be unhappy about it, but complaining isn't going to change anything. You're either going to have to just learn to live with it or not use D.

- Jonathan M Davis

May 12, 2018
On Saturday, 12 May 2018 at 07:39:04 UTC, Jonathan M Davis wrote:
> Ultimately, it's a tradeoff, and arguments can be made for and against. But in practice, it works extremely well. You're certainly free to not like this particular design choice, but it's one that most of us have no problem with, and I'd be shocked to ever see it change. So, you can be unhappy about it, but complaining isn't going to change anything. You're either going to have to just learn to live with it or not use D.
>
> - Jonathan M Davis

I'm not so much complaining about it, as warning others of it.

D modules do NOT (cannot) respect the encapsulation of the class, and therefore, D modules containing classes, can very easily (to borrow a phrase from Bertrand Meyer) start to resemble "a chunk of Swiss cheese that has been left outside for too long..".

As for using D, this is why I don't really use D for anything other than small tasks - where I can happily revert to procedural type programming ( C like), and not have to worry about the issues of broken class encapsulation - which will almost certainly lead to unexpected side-effects, and create whole new 'class' of problems that D programmers have to deal with.

May 12, 2018
On Saturday, 12 May 2018 at 07:07:33 UTC, Jonathan M Davis wrote:

> You obviously don't have to test your private functions if you don't want to, but if you're trying to state that testing private functions is bad practice (and that's very much what it seemed like you were saying when you talked about testing private functions killing unicorns), [...]

Actually Jim Weirich (Rake's creator) at one of Ruby's conferences had a coffee mug with "Every time you test a private method, an unicorn dies".


May 12, 2018
On 5/11/2018 4:27 PM, H. S. Teoh wrote:
> On Fri, May 11, 2018 at 04:14:43PM -0700, Walter Bright via Digitalmars-d wrote:
>> On 5/10/2018 6:22 AM, Piotr Mitana wrote:
>>> For those who never coded Scala and don't know sealed classes: a
>>> sealed class is a class which can be only extended in the same
>>> source file.
>>>
>>>       sealed class MyClass {}
>>>
>>> Translating to D, a sealed class would could only be extended in the
>>> same module.
>>
>>    private class MyClass { }
>>
>> should do the trick.
> 
> It doesn't; if you do this, you can't pass MyClass outside the module
> and have other modules invoke its methods.  They will get an essentially
> opaque object.  You'll have to resort to ugly wrapper types (defined in
> the same module) in order to make this work.

The solution is:

    private class MyClass { ... }
    public final MyClassSealed : MyClass { }

Meaning other modules can use MyClassSealed but cannot derive from it. Other classes inside the module can derive from MyClass as required.
May 12, 2018
On 5/11/2018 4:28 PM, Jonathan M Davis wrote:
> [...]

See my reply to H. S. Teoh.
May 12, 2018
On 5/11/2018 8: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.

Mike's right. D's encapsulation model is designed around the module. If a module is too large to be comprehended, it should be broken up into smaller modules, each with its encapsulated functionality.