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

NotYouAgain NotYouAgain at gmail.com
Thu Apr 25 05:37:24 UTC 2024


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`
     }

// ----





More information about the dip.ideas mailing list