April 27
On Saturday, 27 April 2024 at 07:39:19 UTC, Jonathan M Davis wrote:
>
> What I'm saying is that there isn't actually a problem that needs solving. It's a theoretical issue and not one in reality.

That's nonsense. Almost every oop that looks at D, will discover the problem themselves.
The compiler won't help them.

You assume that oop will comes to D not expecting private to mean private to the type?

They will come to D expecting private to be private to the type.

They will discover the same issue that I've uncovered, and will need to adjust their thinking to that a class is no longer considered a type in oop in D, but a subtype of the module.

Again, Swift done it right. D done it wrong.

oo programmers coming to D will have to live with a programming langauge that does it wrong.

> Programmers routinely program in D without running into any issues with private. Some of them even think that private is private to the class or struct and are surprised years later to find out that it isn't, because they never have problems with it.

They haven't developed an extensive library using class-oriented oop style then ;-)

Most likely, they're using D for its C like capabilities.

> Visibility attributes are necessary for controlling the public API, which D's private does just fine.

No. Visibility is related to the type as well. This is where D got it wrong.

Swift got it right.

> From what I've seen, the only problem that we actually get from it is people being surprised that D's private is private to the module and then who want it to work differently (or who want something like private(this) in addition to private), because they think that it's good OO programming to have that and that it's dirty otherwise.

Why would they be surprised do you think?

Yes, it is good OOp programming to have private attributes.

And 'dirty'? wtf does that mean?

> But from a practical standpoint, I'm not sure that I've ever seen a bug reported that happened because private was for the module and not the type.

private(this) is not about fixing bugs. It's about fixing type design.
It's about fixing unittest so that they actually test the design of the type.

>
> In my experience, there simply isn't anything to worry about here, and usually, the folks who are worried about it are worried about it because it's not what they're used to or because it doesn't fit in with their ideal view of OO programming.

It's about an ideal language in which to do oop.

D claims to support oop. but then insist that they rethink what oop is.

No, I want to do what I know to work. D claims I can do that, but it doesn't live up to that claim.

> It is a topic that I've seen come up periodically over the nearly twenty years that I've been using D, so it's far from new, and it will probably never go away as long as things stay the way that they are...

Enter 'private(this)' .. and you'll never ever have to here about it, ever again ;-)

> but it's almost always newcomers complaining...

And why do you think that is?

Would they be making the same complaint if they used Swift? Not likely.

Serious oo programmers will likely go elsehwere once they discover how D insists they conform to the way D want them to think.

> problems, but private being private to the module really hasn't been causing problems in general.

And yet, so say its a topic that keeps coming up, and will continue to keep coming up.

If it's not causing a problem, perhaps its because to the people to whom it was causing a problem, have gone elsewhere... so it's no longer a problem for D.

> So, yes, I bring up moving code to other modules as a solution if you actually want to guarantee that it doesn't have access to the code in the module that it was in, because that will give you that guarantee. But it's not something that I'm arguing that folks should be doing as best practice, because it simply isn't necessary in practice.

I want that guarantee. In fact, I insist that any language I use provides that guarantee.

I also insist that it doesn't require more effort than what it should.

adding (this) to private, is the less effort possible.

I don't want to see the bugs arise, I want to prevent them from arising, with the least effort possible, from me.

The module is not a type, and the class should not be a subtype of it. The class itself is the type. It should be able to assert control over itself, like other types.

> And because I have not seen anything that private(this) is trying to solve as something that's actually causing problems, I don't see any reason to add a language feature to try to solve those problems.
>
> - Jonathan M Davis

You (and others) provide alternatives to private(this) when people discover those problems, but you (and others) don't see what the problem identified, as a problem, but as a non-problem, but still, one requiring a solution? I don't get the logic in that.

If there is no problem, why propose the one class per module, one unittest per module, solution?

Yes. I know the argument. C++, C#, Java, Swift, Javascipt, Haskell...etc. programmers are the actual problem, not D. They come to D expecting the wrong thing..It's their thinking that is the problem, not D.

That's not a convincing argument. Never has been. Never will be.

private(this) and the problem is no longer there. All those programmers will not be required to change how they think. D might even become popular then.

April 27
On Saturday, 27 April 2024 at 08:29:46 UTC, Arafel wrote:
> ..
> ....
> That being said, I would have very much preferred to have this feature available.

It's great that this idea is attracting some support ;-)

Sadly, it's usually just those against it that voice their opinions.

> Another aspect not being discussed here are synchronized classes...

so, it seems, at least 2 problems indentified in this discussion, can now be solved with private(this).

1 - It can (apparently) resolve an issue with synchronized classes (I' don't pretend to understand them)

2 - It can prevent private(this) members from being accessible in a unittest (where the unittest is outside the scope of the class - which is how i always do them anyway). That is, the unittest can be made to only be able to test the public interface now. The compiler itself will enforce this constraint.

I expect there are alternative solutions to both 1 and 2. But I expect any alternative solution would only solve one of them, and a different alternative solution would be needed to solve the other.

But private(this) can solve both ?

Wow. One solution, to multiple problems. How cool is that!

April 27
On Saturday, April 27, 2024 1:31:10 AM MDT NotYouAgain via dip.ideas wrote:
> On Saturday, 27 April 2024 at 06:48:47 UTC, Jonathan M Davis
>
> wrote:
> > ...
>
> What is your solution to the problem below?
>
> Let me guess:
> (1) don't make the mistake of bypassing the public interface in
> the unittest.
> (2) put the unittest in a separate module.
>
> My solution:
> (1) make x and y private(this) and you cannot make a mistake,
> since the compiler will not let you make that mistake.
>
> // ---
>
> module m;
> @safe:
>
> class C
> {
>      private int x, y;
>
>      invariant()
>      {
>          assert(x == y);
>      }
>
>      void modifyX(int val)
>      {
>          x = val;
>      }
>
>      void modifyY(int val)
>      {
>          y = val;
>      }
> }
>
> unittest
> {
>      C c = new C();
>      c.x = 10; // incorrect use of the type.
> }
> // ---

Why is that an incorrect use of the type? Why should I care whether code within the same module is accessing a private member? It doesn't cause problems with the public API if code does that. And if I don't want code within the module to access the private data then I simply won't write code that does, and if I accidentally write code that does, it's all part of the code that's internal to the module rather than part of the public API, so it's an implementation detail.

It won't matter to the code that's using my module whether I have code in there using a type's private members or not. It might go against some concept that the programmer has of what OO is supposed to look like, but ultimately, it's an implementation detail of the module and irrelevant to any code outside of the module. What matters to the code using your module is whether it works, not how its internals are organized. You could even have whole sections of your class' implementation be private functions that are free functions within the module instead of within the class itself, and it wouldn't matter to anyone using your class.

Is the issue that the code is bypassing the invariant? If your code screws up when accessing private members and doesn't make sure that the invariant is correct before any public member functions are called, then you'll catch it then, because the invariant will fail. So, it's not like this is going to result in your code having bugs. And if the code does ensure that the invariant is correct before any public member functions are called, then it's doing the right thing with regards to the state of the object, and there shouldn't be a problem.

And for most unit tests, accessing the private state of an object is a non-issue (in fact, it's often useful). They need to test that that type and its functions are working correctly, and for most tests, the fact that they have access to the private members either helps them do their job, or it's irrelevant.

It's certainly true that if you want to write a test that is guaranteed to only be able to access the public API of a type that you can't currently put that in the module itself, but that's usually only a concern when writing samples for the documentation (since it's obviously a problem if examples use private members given that users of your code can't do that), and if those are documented unit tests, then they have to follow immediately after the symbol that they're documenting, meaning that private(this) wouldn't help anyway. Those unittest blocks would have to be in a position where they would have access to the private members whether you wanted them to or not in order for the compiler to associate them with the symbols that they're supposed to document and test.

Similarly, private(this) wouldn't help at all with a documented unittest block accidentally using a private member of the module rather than of a particular class or struct. So, if documentation is the concern (and that's usually the place where it would make sense to actually be worried about using private symbols in a test), private(this) is not a solution.

And if you really want to prevent tests that aren't documented unit tests from accessing private members for some reason, to do that with private(this), you're forced to move them outside of the type, making it so that they can't be next to what they're testing, making it a somewhat awkward solution even if it's not as bad as having to move the unit tests into another module.

So, if there's any feature that might be useful here, it isn't a way to lock away your class' private members from the rest of the module; it's a way to tell the compiler that a particular unittest block should be treated as if it were not within the module with regards to which symbols it can access. Then you could write documented unit tests where you had to use imports and the public API rather than having them have access to everything within the module, and you could then be completely sure that none of your examples used anything private (whether it was part of the class or not). And if you really wanted other tests to then not have access to private members for some reason, you could mark those unittest blocks with the same attribute or pragma or whatever it is that that feature used to mark the unittest block as not having access.

But for most code within a module, whether it uses a private member or a public one is just an implementation detail and is irrelevant to any code outside of that module. All that the code outside cares about is that the code works properly, not whether its internals use public or private members. Now, using a member that you didn't intend to would definitely be a problem if it behaved differently, but that really doesn't have anything to do with public vs private, since it could happen with any symbol, and proper testing will catch that.

- Jonathan M Davis



April 27
On Saturday, April 27, 2024 2:39:50 AM MDT NotYouAgain via dip.ideas wrote:
> You (and others) provide alternatives to private(this) when
> people discover those problems, but you (and others) don't see
> what the problem identified, as a problem, but as a non-problem,
> but still, one requiring a solution? I don't get the logic in
> that.
>
> If there is no problem, why propose the one class per module, one unittest per module, solution?

No, all we're saying is that if you think that it's a problem for the module to be treated as the unit of encapsulation, you can have one class per module to get around that. We're not arguing that that's actually how you should be writing your code. How you organize it is up to you. Many of us put quite a few types and functions in the same module and have no problem with it, but we're also not determined to view the class as the unit of encapsulation.

> Yes. I know the argument. C++, C#, Java, Swift, Javascipt, Haskell...etc. programmers are the actual problem, not D. They come to D expecting the wrong thing..It's their thinking that is the problem, not D.
>
> That's not a convincing argument. Never has been. Never will be.
>
> private(this) and the problem is no longer there. All those programmers will not be required to change how they think. D might even become popular then.

Ultimately, D chose to go the route of making the module the unit of encapsulation. Some people don't like that (usually because that doesn't fit with how they want to view OOP), but it's served us well overall, and it's allowed us to have a simpler situation with regards to visibility attributes than some other languages have. Adding an extra layer to it to allow classes to be treated as a unit of encapsulation might satisfy those who want to insist that the unit of encapsulation should be the class for proper OOP, but in practice, it hasn't been necessary for D.

Obviously, it's a design decision with tradeoffs, as most design decisions are, and some people aren't going to agree with it, but it is one that has worked quite well for us overall.

You're free to hate that decision. You're free to propose a change to the language like you're doing to try to get the situation to change. Sometimes, Walter agrees to make a change, and sometimes he doesn't. So, if you're convincing enough, maybe the situation will change, but based on what he's said about this in the past, I fully expect that it will be rejected.

When learning any language, it's bound to be the case that some design decisions of the language do not match what you expect or want. Sometimes, it's because those decisions are bad. Sometimes, it's simply because it's not what you're used to or because it doesn't fit how you want things to work. In some cases, it's something that you ultimately come to agree with and like, whereas in other cases, it's just a part of the language that's permanently annoying. You (and anyone else coming to D) will come to your own conclusions about where D's view on private and the unit of encapsulation falls on that scale.

So, no, I'm not going to argue that C++ or C# or whatever did it wrong. I'm just going to say that D made a different design decision, and it's one that's worked well for us. And assuming that you don't convince Walter to change the language, you'll have to figure out how to best work with how private works in D for as long as you choose to use D. Ultimately, whether D did it better or not, D did it differently, and everyone using D has to deal with how it works. For anyone who insists on treating the class as the unit of encapsulation, it's likely to be annoying, whereas for anyone who's willing to treat the module as the unit of encapsulation, it works quite well.

- Jonathan M Davis



April 27
On Saturday, 27 April 2024 at 09:32:00 UTC, Jonathan M Davis wrote:
>..
>..

Can I suggest we both get off this merry-go-round ;-)

It's not a productive use of my time, nor yours, nor anyone elses who have to read through all this nonsense.

If I understand correctly, you think it's pretty pointless. Fine. Let's leave it at that.

I believe that has been your position for...well.. forever.

I like to hear from others, in regards to what benefits they think private(this) might provide, because if a DIP were to be presented, I can assure you, it wouldn't be saying how pointless this DIP is.

Perhaps Walter could express his opinion, since I really have no idea what it is. I only ever get told that Walter would completely reject any DIP with private(this). If he says he won't even consider it, then even this discussion is pointless. People should just move to openD instead I guess.


April 27

On Saturday, 27 April 2024 at 08:29:46 UTC, Arafel wrote:

>

And "just don't do it" seems quite a bit like "you're holding it wrong". That's just enforcing by convention, and at that point why not go with the python "private" way? Just tell people that they shouldn't do it, and done.

In OOP world you enforce contracts with interfaces, not with access attributes. Do you really come from java?

April 27
On 27/4/24 12:22, Kagamin wrote:
> In OOP world you enforce contracts with interfaces, not with access attributes. Do you really come from java?

I don't understand you. Are you arguing that we don't need `private`, or even visibility, at all, because we should just use interfaces?

Because otherwise, once you accept the need for `private`, then the question is what the limits should be.

D chose "module", which I can understand, but don't share, at least not as the only option. I think the class / scope is a much more natural boundary, as it is for visibility.
April 27
On Saturday, 27 April 2024 at 10:58:17 UTC, Arafel wrote:
> On 27/4/24 12:22, Kagamin wrote:
>> In OOP world you enforce contracts with interfaces, not with access attributes. Do you really come from java?
>
> I don't understand you. Are you arguing that we don't need `private`, or even visibility, at all, because we should just use interfaces?

If you prefer hardcore OOP, yes. Interfaces for contracts is OOP best practice.
April 27
On Saturday, 27 April 2024 at 11:16:08 UTC, Kagamin wrote:
> On Saturday, 27 April 2024 at 10:58:17 UTC, Arafel wrote:
>> On 27/4/24 12:22, Kagamin wrote:
>>> In OOP world you enforce contracts with interfaces, not with access attributes. Do you really come from java?
>>
>> I don't understand you. Are you arguing that we don't need `private`, or even visibility, at all, because we should just use interfaces?
>
> If you prefer hardcore OOP, yes. Interfaces for contracts is OOP best practice.


For me, type integrity is the most important thing.

Well, type integrity is important for any type really, not just a class type.

Imagine if you could put "hello" into an int, simply because the int was in a module with other code, and therefore lost the ability to protect its integrity.

private already exists, and provides the **necessary** support for enscapsulation of the class type from code *outside* the module.

This discussion is really just about a new access modifier => private(this),
to provide better support for encapsulation of the class type from code *within* the module.

There is no argument that the class should not have, or does need to have, the means to protect its type integrity. D has knows it needs this, but only allows it in relation to code outside the module.

I'm saying, I need it in the module, because the one-class per module is not my thing.

If there's disagreement, its because some don't think I need that, and that the one-class per module is all their willing to offer me. They believe a class-type should be a sub-type of a non-type (i.e. the module). That's where I firmly disagree. Ensuring that operations on a class type are compatible with its design, could be left to 'software engineering', sure, but a tool like private(this) provides a mechanism to express that intent 'explicately', which makes the class-type a strong type again. At the moment, its a pretty weak type when other code is in the module with it.

"A strong type is the software engineering superstructure for programs".

That is where I begin my programming. With a strong type, not a weak one, that lacks any real border.

As such, whenever I code my class-type, I want the means to protect its type integrity, regardless of where the surrounding code exists. More importantly, I want the compiler to understand and enforce that integrity. If I didn't need that as well, I could use 'convention', and then ... hope for the best...

But even Javascript learnt, that convention is not enough..

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties

If there is any disagreement to the idea of private(this), it needs to be on the basis that a weak type is fine, and that I should just accept that.

'Pretending' its a strong type by ensuring no other code is the module with it, is a pretty poor solution for a programming language.

I need this tool so that I can explicately declare intended meaning in my type *and* have the compiler on my side enforcing that.

The proof of a type, is in the type of its proof.

April 28
On 27/04/2024 9:18 PM, NotYouAgain wrote:
> so, it seems, at least 2 problems indentified in this discussion, can now be solved with private(this).
> 
> 1 - It can (apparently) resolve an issue with synchronized classes (I' don't pretend to understand them)

It does not resolve them.

It enables a programmer who knows that an issue exists to prevent it.
The same programmer who wrote that module.

It could be solved by doing something like this internally and automatically. No need for a DIP exposing this capability.