May 12, 2018
On Saturday, 12 May 2018 at 06:42:24 UTC, rumbu wrote:
> 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.

I did TDD at a company for three years. Tests didn't survive refactoring.

These days, I have tests to ensure correctness, and they can tell me when public interfaces change. I usually don't need tests to tell me that, but they help just in case.

I also tend to have examples projects for anything more complex, which reduces the amount of trouble I can get myself into. Plus the majority of my code is in applications rather than libraries, so consistent interfaces aren't nearly as important (as long as static typing catches the majority of incorrect calls and contracts catch the rest).
May 12, 2018
On Saturday, 12 May 2018 at 10:27:11 UTC, Walter Bright wrote:
> 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.

It is not. Other modules can use MyClassSealed - yes. Inheritance is possible only im module - yes. But these are two different classes still. If we have two of extending classes:

  private class Parent {}
  public final class Child1 : Parent {}
  public final class Child2 : Parent {}

Then it is true that I can inherit Parent outside the module, but I can't use it as well. In this case I can't create an array (other then Object[]) that can hold both Child1 and Child2 outside the module.

What I want is to see the supertype *everywhere* and be able to use it for example to create an array of Parents, but not be able to create Child3 : Parent elsewhere then in the module where Parent resides.

  public final class ParentSealed : Parent {}

won't help - it will be just the same as two ChildX classes and still won't have a *visible* supertype other then Object with them.

What I am trying to do is:

  /* foo.d */
  module foo;

  sealed class Parent {}
  final class Child1 : Parent {}
  final class Child2 : Parent {}

  /* bar.d */
  module bar;

  import foo;

  static this
  {
      Parent[] twoParents = [new Child1(), new Child2()];  // Parent is still visible
  }

  class Child3 : Parent {}  // ERROR: Parent is sealed and cannot be extended outside module foo

I don't think that it is possible to rewrite this code without sealed, but still having Child3 illegal and the Parent[] array creatable in the module bar.

Another example - taken directly from Scala. In Scala optionals are defined via a set of classes ("[T]" is Scala's version for Java's "<T>"):

  sealed abstract class Option[T] {}
  final case class Some[T] extends Option[T] {}
  object None extends Option[Nothing] {}

For the sake of simplicity let's don't dive in how "case class" and "object" are different from typical classes. Also let's assume that Nothing extends T (in fact Scala's Nothing extends every possible type)

 You can declare an Option[Int] variable everywhere and assign Some(value) or None to it. All three classes are visible from everywhere, but as Option is sealed, you can't create

  class OnlyOnMonday[T] extends Option[T] {}

in the other module (effectively nowhere, as Option is a part of the standard library).

May 12, 2018
On 5/12/2018 8:18 AM, Piotr Mitana wrote:
> What I am trying to do is:


========== a.d ============

class P
{
    private this();
}

final class C1 : P { }
final class C2 : P { }

======== test.d ============

import a;

void foo()
{
    P[] twoPs = [ new C1(), new C2() ]; // works
}

class C3 : P   // fails
{
}

============================

dmd test a
Error: constructor a.P.this is not accessible from module test
May 12, 2018
On Saturday, 12 May 2018 at 13:38:18 UTC, Walter Bright wrote:
>
> Mike's right. D's encapsulation model is designed around the module.

Actually, that is not true. If it were true, then I could do:

------------
module test;
void main() { i = 2; }  // sorry, but i belongs to another unit of encapsulation
void foo() { int i = 1; }
------------

D only breaks the encapsulation properties of classes, not functions.

Since the vast majority of programmers use classes as the basis for encapsulation, this surely presents a significant problem to those coming over to D, rightly expecting that encapsulation to be retained.

> If a module is too large to be comprehended, it should be broken up into smaller modules, each with its encapsulated functionality.

But that's why we have functions and classes - which are their own level of smaller units of encapsulation. Blurring the boundary of encapsulation seems like a big step backward in terms of structured programming.

Each unit of code (a function, a class, a module) should respect the encapsulation properties of each other.

There's simply no point in using classes in D, as they have no capacity to encapsulate themselves (whereas function still retain this privilege)

Now if 'private' meant 'private to the class' (as most people would rightly expect), and the default if you had no attribute was, say, 'accessible to the module', then I could probably live with that, and I would start to use classes in D productively.

But when the class has lost its capacity to encapsulate, it's lost its purpose.

It is hard enough to hold a class in working memory so you can reason about.

Making us hold whole modules in memory so we can reason about the interaction between classes and modules, is just nonsense, in my opinion.

May 12, 2018
On Saturday, 12 May 2018 at 15:48:53 UTC, KingJoffrey wrote:

>
> Actually, that is not true. If it were true, then I could do:
>
> ------------
> module test;
> void main() { i = 2; }  // sorry, but i belongs to another unit of encapsulation
> void foo() { int i = 1; }
> ------------
>
> D only breaks the encapsulation properties of classes, not functions.

> But that's why we have functions and classes - which are their own level of smaller units of encapsulation. Blurring the boundary of encapsulation seems like a big step backward in terms of structured programming.
>
> Each unit of code (a function, a class, a module) should respect the encapsulation properties of each other.

Encapsulation and scope are not the same thing.

>
> There's simply no point in using classes in D, as they have no capacity to encapsulate themselves

Yes, they do. The private API is not visible to the outside world.


>
> Now if 'private' meant 'private to the class' (as most people would rightly expect), and the default if you had no attribute was, say, 'accessible to the module', then I could probably live with that, and I would start to use classes in D productively.

I'm using classes productively right now. Having private class members accessible in the module is a boon, not a hindrance, IMO.

>
> But when the class has lost its capacity to encapsulate, it's lost its purpose.

It hasn't lost its ability to encapsulate. The private implementation is hidden from the outside world and does not impact the public API.

>
> Making us hold whole modules in memory so we can reason about the interaction between classes and modules, is just nonsense, in my opinion.

No, nonsense would look like this:

```
module mymmod;

class Foo {
   private int _x;
   /* module private */ int x() { return _x; }
}

class Bar {
   private int _y;
   /* module private */ int y() { return _y; }
}

void printFooBar(Foo f, Bar b) {
   import std.stdio : writefln;
   writefln("f.x = %s, b.y = %s", f.x, b.y);
}
```

Thank goodness we don't have to do this silliness.



May 12, 2018
On Saturday, May 12, 2018 08:13:12 KingJoffrey via Digitalmars-d wrote:
> 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.

Honestly, the only time that I've ever seen problems related to the fact that private relates to the module and not the struct or class is when there's a problem with a unit tests due to the fact that it's not restricted in the same way that user code would be e.g. - if a symbol is accidentally private, the unit test won't catch that.

I have never seen encapsulation issues where someone accidentally uses some private piece of a class or struct by accident elsewhere in the module, and the code therefore ends up with a bug. I'm not about to claim that it's impossible to make such a mistake, but I've never seen one, and in my experience, the fact that everything in a module can access everything else in a module (except that functions can't reach into each other) is a complete non-issue and if anything makes life simpler, because it completely negates the need to worry about friends in those cases where you really do need to reach into the innards of a class or struct within the module.

To many of use, you're making a mountain out a mole hill here. While I can understand why what D has done with private might be disturbing to someone when they first come to D, in practice, it's proven to work quite well without causing unexpected side-effects and stray bugs. Maybe it would be worse if D didn't encourage unit testing the way that it does (I don't know), but I can unequivocably say that what D has done with private has worked wonderfully for me and most of the programmers who use D.

- Jonathan M Davis

May 12, 2018
On 5/12/2018 9:42 AM, Mike Parker wrote:
> Thank goodness we don't have to do this silliness.

I always thought the 'friend' business in C++ was an awful hack. But C++ didn't have modules, and modules are a much better solution to that problem.
May 13, 2018
On Saturday, 12 May 2018 at 18:36:59 UTC, Walter Bright wrote:
> On 5/12/2018 9:42 AM, Mike Parker wrote:
>> Thank goodness we don't have to do this silliness.
>
> I always thought the 'friend' business in C++ was an awful hack. But C++ didn't have modules, and modules are a much better solution to that problem.

Modules would only be a better solution, if, and only if, the programmer still had control over class level encapsulation.

At least 'friend' in c++, is in the control of the programmer.

D has decided the programmer doesn't need this control anymore, takes that control away, and gives it to the module - the programmer has no say in it - even if the programmer want's it private, the module overrides private!!

I would expect, that like me, 10's of millions of other programmers would not be comfortable with this.

That the '< 1000' D programmers think otherwise, doesn't make the case.

Go back and give the programmer control, as to whether the class or the module has the greater authority, and perhaps...then... D will attract more programmers.

Feel free to show the code below, to all the C#/C++/Java programmers out there - I'm sure they'll love what D has done with the class-module interaction.

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

import std.stdio : writeln;

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

    writeln(p.getName); // I designed my class to present this interface.
    writeln(p._name); // The module couldn't care less about your interface.

    p._name = "King Walter"; // even worse, the module can de-throne the 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 13, 2018
On Saturday, 12 May 2018 at 18:19:48 UTC, Jonathan M Davis wrote:
>
> I have never seen encapsulation issues where someone accidentally uses some private piece of a class or struct by accident elsewhere in the module, and the code therefore ends up with a bug.

Then you've never seem me program.

That bug you mention, is something that has often popped up in my program, because the compiler didn't warn me - hey, that stuff is private, shouldn't you be using the getter, or setter.

This loss of encapsulation, is why I no longer use classes in D.



May 13, 2018
On Sunday, 13 May 2018 at 01:52:20 UTC, KingJoffrey wrote:
> On Saturday, 12 May 2018 at 18:36:59 UTC, Walter Bright wrote:
>> On 5/12/2018 9:42 AM, Mike Parker wrote:
>>> Thank goodness we don't have to do this silliness.
>>
>>[...]
> ================================
> module test;
>
> import std.stdio : writeln;
>
> void main()
> {
>     Person p = new Person("King Joffrey");
>
>     writeln(p.getName); // I designed my class to present this interface.
>     writeln(p._name); // The module couldn't care less about your interface.
>
>     p._name = "King Walter"; // even worse, the module can de-throne the 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!";
>     }
> }
>
> ===========================================

Again, all you have to do is put class Person in a separate module. Its not that hard. Why is main in the same module if it isn't logically related to Person? It should be in its own module. Its uses Person. main does not extend person, it needs only the public bits. So it goes in its own module. And please, if this bothers you so much, start a new thread. You're spamming someone else's feature request by going off topic.