February 15, 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:

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:

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:

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:

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:

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.

February 15, 2023

On Wednesday, 15 February 2023 at 08:56:00 UTC, Mike Parker wrote:

>

If private were restricted to the class/struct, it would add anything more for encapsulation in D.

I meant to say, it "wouldn't add more".

February 15, 2023
On Wednesday, 15 February 2023 at 08:57:27 UTC, Mike Parker wrote:
> On Wednesday, 15 February 2023 at 08:56:00 UTC, Mike Parker wrote:
>
>> If private were restricted to the class/struct, it would add anything more for encapsulation in D.
>
> I meant to say, it "wouldn't add more".

Well, to quote Stroustrup (from that paper I cited):

"A language is said to support a style of programming if it provides facilities that makes it convenient (reasonably easy, safe, and efficient) to use that style. A language
does not support a technique if it takes exceptional effort or skill to write such programs; it merely enables the technique to be used."

If the only way to protect hidden data within a user-defined type (lets call it a class.. or whatever you want) from other code within the module is to put that type in it's own module, I would argue that D 'enables' data hiding, but does not 'support' it. Of course, I am referring to the context of a module, and any code within that module.

The benefit of having the ability to 'not have to' put a user-defined type in a module by itself, simply to enforce data hiding (from other code in a module), seems pretty obvious to me. For example, you could put tightly coupled classes in the same module, and each class would not be able to access the hidden parts of each other (except through an explicit declaration). You'd be able to put unit-tests in the same module, and not have those unit-tests accessing hidden data of your type. Etc...etc.

So the benefit is clear.

The downside? I (as yet) have never heard a convincing argument for why D should never provide such an option to the programmer, but should instead, continue to force programmers in to the 1-type-per-module design (which is an entirely unreasonable contraint for a language to enforce on a programmer).

btw. This is not about beating a horse. I think the point was raised in some comment, and various people (the usual ones, including yourself) have decided to weigh in. That is what results in the converstaion being had ;-)

February 15, 2023

On Wednesday, 15 February 2023 at 08:57:27 UTC, Mike Parker wrote:

>

I meant to say, it "wouldn't add more".

What if two classes in the module that are several meters apart make mistakes that change the privite variable of another class?

No one can guarantee that after a few months, even if you are the author, you will not make mistakes, so as to misuse private variable, while class level private can be completely avoided it!

There is no maintainability, because two out-of-class functions may quietly change your private variables.

February 15, 2023
On Wednesday, 15 February 2023 at 07:23:39 UTC, thebluepandabear wrote:
> On Wednesday, 15 February 2023 at 02:14:30 UTC, Mike Parker wrote:
>> On Wednesday, 15 February 2023 at 01:16:00 UTC, thebluepandabear wrote:
>>
>>>
>>> I think what you could say is that D lacks _encapsulation_ which is also an OOP concept. So D is partially OOP but not fully OOP due to there being no encapsulation in the language.
>>
>> D does not lack encapsulation, it's just that the unit of encapsulation is the module. Everything private in a module is encapsulated from the perspective of the public API.
>>
>> If you really want to prevent anything inside a module from accessing the private parts of a class, you can put the class in its own module.
>>
>> Must we continue beating this horse?
>
> Why is the unit of encapsulation the module though? Makes no sense.


It does make sense. But not if the language also provides user-defined types. That is explained in the Stroustup paper I cited.

That is, a language that provides modules as well as user-defined types, should provided encapsulation for both. D does that, but for user-defined types it doesn't in the context of other code in the same module as that type. That is why in D you are 'forced' to put that type in its own module 'just' to encapsulate it from other code that would have otherwise been in the same module.

No. It makes no sense. A user-defined type should be able to protect hidden data from other code within the same module. That really doesn't sound that extreme to me ;-)

February 15, 2023

On Wednesday, 15 February 2023 at 09:51:41 UTC, zjh wrote:

>

On Wednesday, 15 February 2023 at 08:57:27 UTC, Mike Parker wrote:

>

I meant to say, it "wouldn't add more".

What if two classes in the module that are several meters apart make mistakes that change the privite variable of another class?

No one can guarantee that after a few months, even if you are the author, you will not make mistakes, so as to misuse private variable, while class level private can be completely avoided it!

There is no maintainability, because two out-of-class functions may quietly change your private variables.

In a module that contains a class, and other code as well (perhaps other tightly coupled classes), you can know nothing at all about that type (or any other class) without knowing everything else in the module. If one understands this, then one understands the problem here ;-)

.. btw. other code.. includes unitests as well.

The solution that D provides, is not a solution. It's a design constraint being forced on programmers. Anyone that argues otherwise, is speaking out of their ...

February 15, 2023

On Wednesday, 15 February 2023 at 09:51:41 UTC, zjh wrote:

>

What if two classes in the module that are several meters apart make mistakes that change the privite variable of another class?

No one can guarantee that after a few months, even if you are the author, you will not make mistakes, so as to misuse private variable, while class level private can be completely avoided it!

There is no maintainability, because two out-of-class functions may quietly change your private variables.

I referenced that in my post. The exact same problem exists inside the class when your class file is very long. You can easily manipulate the private member even when it's only supposed to be accessed by a specific function. A common recommendation in Java used to be (and probably still is) to always accessing private members by their setters even inside the class. And after all these years they haven't had a need to lock down single-method access to private members. It's the exact same thing in D: the private implementation is in the source file. The fact that the source file represents a module rather than a single class is irrelevant.

We keep repeating the same arguments over and over and over again on this. I still haven't seen any convincing argument for changing things when it's already possible to do what you want to do. I repeat for the umpteenth time: if you care so much about who can touch your private parts, then put your classes and structs in their own modules and use D's package facilities to provide the public interface you want.

February 15, 2023

On Wednesday, 15 February 2023 at 10:17:30 UTC, Mike Parker wrote:

>

I referenced that in my post. The exact same problem exists inside the class when your class file is very long. You can easily manipulate the private member even when it's only supposed to be accessed by a specific function. A common recommendation in Java used to be (and probably still is) to always accessing private members by their setters even inside the class. And after all these years they haven't had a need to lock down single-method access to private members. It's the exact same thing in D: the private implementation is in the source file. The fact that the source file represents a module rather than a single class is irrelevant.

We keep repeating the same arguments over and over and over again on this. I still haven't seen any convincing argument for changing things when it's already possible to do what you want to do. I repeat for the umpteenth time: if you care so much about who can touch your private parts, then put your classes and structs in their own modules and use D's package facilities to provide the public interface you want.

Class level private, which can ensure that there will never be any leakage and there will be no encapsulation misuse,
At the module level, this is unavoidable!
And there are closely related classes, which should be placed in a module.

February 15, 2023
On Wednesday, 15 February 2023 at 10:17:30 UTC, Mike Parker wrote:
>
> We keep repeating the same arguments over and over and over again on this. I still haven't seen any convincing argument for changing things when it's already possible to do what you want to do. I repeat for the umpteenth time: if you care so much about who can touch your private parts, then put your classes and structs in their own modules and use D's package facilities to provide the public interface you want.

The convincing arguement (convincing to me anyway) was made when I came to D, programmed a class, and put a unittest in the same module, and accidently referenced hidden data of my class in my unittest. This result in a bug. It was when i was tracking down the source of this bug, that I discovered that private is not private at all (inside the module).

If there is a cycle continuing, it's because your solution to a 'real' problem (read above again please), is to force an unreasonable design constraint onto the programmer.

This includes being forced to put your unittest in its own module as well (for reasons demonstrated above).

It should be up to the programmer to decide what types should go into their module: Not the language! You think the language has this right to force such a constraint onto the programmer, I do not. That really is the basis for the disagreement here.

I want fewer modules, each containing tighly couple types.

You want more modules, each containing one single type.

I want unittest in the same module as my type.

You want me to have them in their own module as well.

No. I cannot accept this as a reasonable solution.
February 15, 2023
On Wednesday, 15 February 2023 at 08:56:00 UTC, Mike Parker wrote:
>
> 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.

It seems the only beating go on here, is the beating your handing out.

If someone raises a comment about type private, and you all jump in any beat on him, then who is the real victim here?

Try to keep it about language design, and stop getting personal.