Non-ugly ways to implement a 'static' class or namespace?

Mike Parker aldacron at gmail.com
Wed Feb 15 08:56:00 UTC 2023


On Wednesday, 15 February 2023 at 07:23:39 UTC, thebluepandabear 
wrote:

>
> Why is the unit of encapsulation the module though? Makes no 
> sense.

What is the purpose of encapsulation? To keep the implementation 
details hidden behind the public API, such that changing the 
implementation doesn't change the API.

Consider this:

```d
module gfx;
struct Point {
     private int x, y;
     this(int x, int y)
     {
         this.x = x;
         this.y = y;
     }

     void move(Point to) {
         x = to.x;
         y = to.y;
     }
}
```
Here, `move` is part of the public API. `x` and `y` are part of 
the implementation. Nothing outside the module can touch them.

Now this:

```d
module gfx;
struct Point {
     private int x, y;
     this(int x, int y)
     {
         this.x = x;
         this.y = y;
     }
}

void move(ref Point from, Point to) {
     from.x = to.x;
     from.y = to.y;
}
```

 From the perspective of the public API, nothing has changed. The 
following works in both cases:

```d
Point p;
p.move(Point(10, 20));
writeln(p);
```

In both cases, the implementation is hidden behind the same 
public API.

If private were restricted to the class/struct, it would add 
anything more for encapsulation in D. In practical terms, if you 
are editing the `gfx` module, you also have access to the 
implementation details of `Point`.

Sure, if you have e.g., a special setter that does some extra 
work when a member variable is set, you want to ensure that only 
that setter is used to change the member variable. But that's 
true *inside the class/struct* as well.

I mean, just consider this:

```d
class C {
     private enum minX = -100;
     private int _x;

     void setX(int newX) { _x = newX > minX ? newX : minX }

     void doSomething(State s) { setX(_x + s.val); }
}
```

vs. this:

```d
class C {
     private enum minX = -100;
     private int _x;

     void setX(int newX) { _x = newX > minX ? newX : minX }
}

void doSomething(C c, State s) { c.setX(c._x + s.val); }
```

Ideologically, they are not the same. In practical terms, they 
are. Whether the closing brace of the class declaration is before 
or after `doSomething` matters not one bit. Yes, things can go 
wonky in a module that's many lines long and someone sets `_x` 
from outside of the class. So what? The same is true for a class 
that's many lines long when someone adds a new method that 
directly sets `_x` rather than going through the setter.

D's modules are intended to be used for grouping related 
constructs. Everything in the module is part of the same private 
implementation. If the constructs aren't related, then put them 
in separate modules. And there's still a solution for anyone with 
a strict ideological preference regarding related constructs: 
they can put their classes and structs in individual modules 
under a common package. `package` protection can be used for 
cross-module access inside the package, and the entire set can be 
presented to the outside world as a single module with 
`package.d`.

Our friend of many forum handles misses no opportunity to return 
to this putrid horse corpse to beat it some more, but the meaning 
of private isn't going to change. This is D's approach to 
encapsulation.



More information about the Digitalmars-d-learn mailing list