Jump to page: 1 210  
Page
Thread overview
Extending D's support for object-oriented design with private(this)
Apr 25
Kagamin
Apr 25
bachmeier
Apr 25
zjh
Apr 25
Dom DiSc
Apr 25
monkyyy
Apr 26
monkyyy
Apr 26
Kagamin
Apr 27
zjh
Apr 27
zjh
Apr 27
Arafel
Apr 27
Kagamin
Apr 27
Arafel
Apr 27
Kagamin
Apr 27
Kagamin
Apr 27
Dukc
Apr 27
Arafel
Apr 28
Dukc
Apr 29
Dukc
Apr 29
Basile B.
Apr 30
Dom DiSc
April 25

TITLE: Extending D's support for object-oriented design with private(this)

NOTE: Only civil and well-informed discourse on this idea is welcome.

DIP forum guidelines are here: https://github.com/dlang/DIPs/blob/master/docs/guidelines-forums.md

BEGIN:

This DIP idea, relates to extending D's support for object-oriented design - by allowing private visibility to be attached to a class member.

The proposal creates no new limitations and no code breakage.

BACKGROUND:

The class type is the core building-block of class-based object-oriented design.

The facility for abstract, structured reasoning about a class type comes from its support for encapsulation.

D provides a class type, which in turn allows D to support class-based object-oriented design, with encapsulation, inheritance, and polymorphism.

see: https://dlang.org/spec/class.html

However, D's minimal encapsulation unit is actually a module, not a class.

That is, class private members are actually private module members, not private class members.

Although private class members cannot be interacted with from another module, they can be interacted with using code inside the same module (but outside of that class).

That's because (in D) the module, not the class, is the encapsulation unit.

Example (code in the same module - but outside of the class definition - accessing a private class member):

// --
module m;

class C
{
  private int _count; // visibilty of this member extends to the entire module.
}

unittest
{
  C c = new C();
  c._count = 42;
}

// ----

D also provides another form of encapsulation for 'a set of modules', when those modules all belong to the same package.

As such, a private class member cannot be interacted with from other modules that don't belong to the same package, but can be interacted with using code inside any of
the modules belonging to that package.

D's insistance (and apparent zealous protection) for having the module as the minimal encapsulation unit, is inconsistent with object-oriented design, where the class is itself a unit of encapsulation.

This has the following consequences:

(1) It makes it difficult to reason about a class definition in a module, when there is other code in the module, as all other code in the module is in essence a part of the class definition.

(2) It allows for accidental, unintended use of a private member by other code in the module, including unittests.

// --
module m;

class C
{
  private int _count; // visibilty of this member extends to the entire module.
  public void setCount(int c) { _count = c; }
}

unittest
{
  C c = new C();
  c._count = 42; // Actually, this is a mistake, and the programmer should be testing the public method setCount(..)
}

// ----

(3) One can only 'simulate' class-based encpasulation in D, by putting each class in its own module. This is, apparently, what is recommended whenever this topic is raised in the forums.

Both (1) (2) (3) can be fully resolved by adding private(this) functionality, as demonstrated here:

// --
module m;

class C
{
  private(this) int _count; // visibilty of this member is contained within this type
}

unittest
{
  C c = new C();
  c._count = 42; // Error: data member _count is an inaccessible (private)property of type `m.C`
}

// ----

April 25
Apart from literature review type content, there isn't much to discuss here. There is nothing to tune.

I suggest you start work on a draft DIP and move to development unless Walter or Atila have strong opinions against it.
April 25

On Thursday, 25 April 2024 at 05:37:24 UTC, NotYouAgain wrote:

>

TITLE: Extending D's support for object-oriented design with private(this)

This improvement has no side effects on the d language. I really don't know why they oppose it?

April 25

On Thursday, 25 April 2024 at 06:05:23 UTC, zjh wrote:

>

This improvement has no side effects on the d language. I really don't know why they oppose it?

Opposition was only because of "friend"s, which destroys encapsulation in an unpredictable manner. As long as no "friend" attribute is proposed, everything is fine. Already works without problems in OpenD.

April 25

On Thursday, 25 April 2024 at 08:08:40 UTC, Dom DiSc wrote:

>

On Thursday, 25 April 2024 at 06:05:23 UTC, zjh wrote:

>

This improvement has no side effects on the d language. I really don't know why they oppose it?

Opposition was only because of "friend"s, which destroys encapsulation in an unpredictable manner. As long as no "friend" attribute is proposed, everything is fine. Already works without problems in OpenD.

If my understanding is correct, the concern was not about 'friends' but 'C++ like' friends.
That is, friends that could essentially be anywhere.....and difficult to track down.

But D also has a 'friends' notion, implicately. That is, all code in the module is essentially a friend of any class in the module, and within a package of modules, that notion extends further. It's implicit in D, because the module is the unit of encapsulation, not the class.

So I'd say that D understands the necessity for a friend feature - it just restricts the borders of its use (i.e. to the module, or a package of modules).

This idea never involved the concept of 'C++ like' friends, nor would it even be needed, since a more suitably 'constrained border' for friendship is already in D - i.e. the module (or modules within a package).

And yes, I'm not aware of any problems using this feature that is already in OpenD ;-)

April 25

On Thursday, 25 April 2024 at 05:53:18 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

Apart from literature review type content, there isn't much to discuss here. There is nothing to tune.

Nested classes.

April 25
On Thursday, 25 April 2024 at 05:53:18 UTC, Richard (Rikki) Andrew Cattermole wrote:
> Apart from literature review type content, there isn't much to discuss here. There is nothing to tune.
>
> I suggest you start work on a draft DIP and move to development unless Walter or Atila have strong opinions against it.

I'd like to see more discussion first.

There are implications for derived classes (that are in the same module), and nested classes (which of course, are already in the same module).

The feature would also open up the following 'new idiom' for creating and 'enforcing' pseudo static classes in D (which I like and use in OpenD). Some, I believe, may object to allowing such an idiom in D - but they should put forward their reasoning along with their objection.

module m;
@safe:

import std;

final class C // final -> class cannot be derived from
{
    private(this) this(){}  // no instance of this class is possible
                            // **not even by other code in the same module.

    private void test() {}; // although non-static members are allowed, but pointless,
                            // since they can never be used - because of private(this)

  static:
    private(this) string message = "Hello!";
    void sayHello() { writeln(message); }
}

unittest
{
    C c = new C(); //  Error: class `test.C` constructor `this` is not accessible
    writeln(C.message); // Error: property `message` is private to type `test.C`

    // static members are callable on a class even when no instance of the class exists.
    C.sayHello(); // ok
}

April 25

On Thursday, 25 April 2024 at 05:37:24 UTC, NotYouAgain wrote:

>

Both (1) (2) (3) can be fully resolved by adding private(this) functionality, as demonstrated here:

// --
module m;

class C
{
  private(this) int _count; // visibilty of this member is contained within this type
}

unittest
{
  C c = new C();
  c._count = 42; // Error: data member _count is an inaccessible (private)property of type `m.C`
}

// ----

This introduces a more restricted version of private. Overloading private to give it a second meaning is going to cause confusion for new users and really anyone that doesn't use D's OOP all the time. I recommend using something like hidden or strongprivate.

April 25

It should say whether __traits(getMember), allMembers and .tupleof can access private(this) members.

private(this) maybe should be the default for synchronized classes.

BTW regarding unit tests, I would like to have public unittest disallow access to anything non public. Perhaps if accepted, there could later be private(this) to opt-in to accessing those fields. That is important when the class is a template and you don't want the test instantiated every time the template is instantiated.

April 25

On Thursday, 25 April 2024 at 05:37:24 UTC, NotYouAgain wrote:

>

[…]

I don’t know why, but I find private(this) looks weird. It makes me think I can put other things in the parentheses – which is not the case. How about super private? super is already a keyword. Yes, it’s a little bit tongue-in-cheek, but I honestly like it more than private(this).

« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10