www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - `restricted` member variables

reply Mike Parker <aldacron gmail.com> writes:
I won't rehash the private-to-the-module debate here. I've always 
looked at it purely in terms of the public vs. private interface. 
 From that perspective, I still don't find the argument that "it 
breaks encapsulation" a convincing one on the surface. However, 
[this example from Max 
Samukha](https://forum.dlang.org/post/yhrioqcjmnipkrvlrpve forum.dlang.org)
goes below the surface:

```d
synchronized class C
{
     private int x;
     private int y = 1;

     invariant() { assert(y == x + 1); }
}

void foo(C c, int x)
{
     c.x = x;
     c.y = x + 1;
}
```

That made me do a double take. Consider also, in place of an 
`invariant`, a setter with a precondition like so:

```d
class D
{
     private int _x;

     void x(int newX)
     in (newX >= 100 && newX < 1000)
     {
         x = newX;
     }
}

void main()
{
     D d = new D;
     d._x = 10;
}
```

In each case, directly accessing the variable elsewhere in the 
module bypasses all the checks.

So, the obvious solution, the same solution I have suggested 
numerous times in the private-to-the-module debate, is to move 
the class to a separate file. If all we are talking about is the 
public  vs. private interface, and not the consequences of 
bypassing contracts and synchronization, then that's a suitable 
solution.

Unfortunately, this is a poor solution when synchronization and 
contracts are in the picture. It means these features are only 
fully effective when a class is in its own file.

Moreover, the precondition on `D.x` can be bypassed within the 
class itself, so moving it to a separate module doesn't make that 
problem go away. Any member function can write to `_x` without 
going through `x`.

The other argument I make in the private-to-the-module debate, 
which again still holds if all we're talking about is `private`, 
is that it doesn't matter---if you have access to the file, then 
you have access to the private members anyway.

And that doesn't hold here either. `private` is intended to be 
accessible inside the module. Any constraints on access are 
arbitrarily set by convention (e.g., style guides). Class-level 
synchronization is intended to kick in on every function call. 
Invariants *are* documented to say that "relationships must hold 
for any interactions with the instance from its public 
interface", but then what's the point if it's so easily broken 
from elsewhere in the module?

And then there's function contracts, particularly on functions 
that write to member variables like in my example. This is a 
cheaper form of invariant in that it's only applied to this 
function and not to all functions in the class. But  again, it's 
so easy to bypass.

 From that perspective, I see massive gaping hole here. I've done 
a complete 180 on need for further restricting member variable 
access. But I'm seeing it more granularly than class-level and 
down to the function level.

After some spitballing, here's something I like:

```d
class E
{
    restricted int _y;
    restricted(_y) void y(int newY) { _y = newY; }
}
```

A restricted member variable `_y` can only be accessed in 
functions explicitly marked `restricted(_y)`. No other member 
function can access that variable, and therefore neither can 
anything in the broader module.

The function `y` is implicitly private, meaning it follows the 
rules of any private member (private-to-the-module). The `_y` 
parameter to `restricted` indicates not that the function itself 
is restricted, but that it is allowed to access `_y`. So then 
this is also possible:

```d
restricted(_y) protected foo { // okay to access _y }
restricted(_y) public bar { // ditto }
```

I imagine this would be useful:

```d
restricted {
    int _y;
    void y(int newY} { _y = newY};
}
```

Any function declared in this restricted block has access to 
`_y`. Multiple variables in a single block could be possible:

```d
restricted {
    int _x, _y;
    void foo() { // this function is implicitly  restricted(_x, 
_y) }
}
```

Restricted blocks are independent of each other. Functions in 
this block can't access member variables in other blocks.

One benefit of this would be that by tightly restricting write 
access to a single setter function like `y()`, any `in` contract 
that validates the new value is effectively a class invariant, 
but it's only run when this function is called instead of for 
every function in the class.

Should restricted member functions be allowed? E.g.:

```d
class F {
     restricted foo() { ... }
     restricted(foo) bar { ... }
}
```

I don't know. If so, then functions in restricted blocks then be 
implicitly `restricted` rather than `private`.

============

Anyway, I thought I'd throw this out there for comment. Maybe 
someone will come up with a better idea, or take this one and run 
with it. Regardless, I can't be the one to write a DIP for it 
since I'm the DIP manager. So if anyone wants to, feel free.

Also, I haven't discussed this with anyone else yet, so I have no 
idea what Walter or Atila would say about it.

Destroy!
Jun 20 2022
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 Destroy!
The simple way out of this is that, if it touches thee class's privates parts, it ought to run the invariant checks.
Jun 20 2022
next sibling parent user1234 <user1234 12.de> writes:
On Monday, 20 June 2022 at 11:16:40 UTC, deadalnix wrote:
 On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 Destroy!
The simple way out of this is that, if it touches thee class's privates parts, it ought to run the invariant checks.
yes, +1. The fact that invariants are currently not called can be seen as a bug. The bug fix is to call them, not to create a new syntax.
Jun 20 2022
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Monday, 20 June 2022 at 11:16:40 UTC, deadalnix wrote:

 The simple way out of this is that, if it touches thee class's 
 privates parts, it ought to run the invariant checks.
That was my first thought. But then there's the case of the function contracts. That's what led me to this. If my only invariant is the state of a single member variable, then I really only want it checked on the function(s) that actually write to it.
Jun 20 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 20 June 2022 at 11:28:45 UTC, Mike Parker wrote:
 If my only invariant is the state of a single member variable, 
 then I really only want it checked on the function(s) that 
 actually write to it.
Do you want all this complexity just to avoid using «hidden» for marking fields class-private? Also, you need to be able to disable invariants, which adds even more complexity.
Jun 20 2022
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Monday, 20 June 2022 at 11:57:23 UTC, Ola Fosheim Grøstad 
wrote:

 Do you want all this complexity just to avoid using «hidden» 
 for marking fields class-private?
No. I still think class private by itself is pointless in D.
 Also, you need to be able to disable invariants, which adds 
 even more complexity.
I don't see how that changes beyond what we have now with the command line.
Jun 20 2022
parent David Gileadi <gileadis NSPMgmail.com> writes:
On Monday, 20 June 2022 at 12:04:27 UTC, Mike Parker wrote:
 On Monday, 20 June 2022 at 11:57:23 UTC, Ola Fosheim Grøstad 
 wrote:

 Do you want all this complexity just to avoid using «hidden» 
 for marking fields class-private?
No. I still think class private by itself is pointless in D.
Too bad: `class private` is such an excellent ~~color for the bike shed~~ keyword pair.
Jun 20 2022
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Monday, 20 June 2022 at 11:57:23 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 20 June 2022 at 11:28:45 UTC, Mike Parker wrote:
 If my only invariant is the state of a single member variable, 
 then I really only want it checked on the function(s) that 
 actually write to it.
Do you want all this complexity just to avoid using «hidden» for marking fields class-private? Also, you need to be able to disable invariants, which adds even more complexity.
"We have problem A and to solve it we have solution B, but solution B is too broad so solution C is proposed because it solves problem D which is caused by problem A, but we don't believe problem E is a real problem, so solving A using C we have created problem F which requires solution G." Pretty much where we're at.
Jun 20 2022
parent Salih Dincer <salihdb hotmail.com> writes:
On Monday, 20 June 2022 at 12:05:21 UTC, bauss wrote:
 On Monday, 20 June 2022 at 11:57:23 UTC, Ola Fosheim Grøstad 
 wrote:

 "We have problem A and to solve it we have solution B, but 
 solution B is too broad so solution C is proposed because it 
 solves problem D which is caused by problem A, but we don't 
 believe problem E is a real problem, so solving A using C we 
 have created problem F which requires solution G."
It can't be that complex...:) At the very least, we should solve it just like other languages did. SDB 79
Jun 20 2022
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 but then what's the point if it's so easily broken from 
 elsewhere in the module?
You seemingly ask for a puristic language. But what's the point of a puristic language? Why do you think it's better than a practical language?
Jun 20 2022
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 20 June 2022 at 11:59:05 UTC, Kagamin wrote:
 On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 but then what's the point if it's so easily broken from 
 elsewhere in the module?
You seemingly ask for a puristic language. But what's the point of a puristic language? Why do you think it's better than a practical language?
Well, class invariants require full encapsulation. Either way, the proposed solution won't work, because you only want to check the invariant when you exit "the penetration of the object capsule". It is perfectly ok that the invariant is broken once you are inside the "object capsule method". It is only when you leave the initial method that "entered the object capsule" that the invariant should be checked. Methods are clear gateways, free standing functions are not.
Jun 20 2022
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On Monday, 20 June 2022 at 11:59:05 UTC, Kagamin wrote:
 On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 but then what's the point if it's so easily broken from 
 elsewhere in the module?
You seemingly ask for a puristic language. But what's the point of a puristic language? Why do you think it's better than a practical language?
Uh, no. This isn't about purity. I don't care about it in the absence of invariant, synchronized, and function contracts. And I'd be happy with fixing simply fixing the invariant/synchronized hole by triggering them on member variable accesses. That would be preferable to adding a new feature. That said, I like the idea of going one step further in the case of contracts and, as I mentioned, allow cases where you can treat a contract like a single-function invariant by restricting member variable access to a specific set of functions. I put this out there to see if anyone else likes it, and to discuss if a feature like this is worth the added complexity.
Jun 20 2022
prev sibling next sibling parent Dom Disc <dominikus scherkl.de> writes:
On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 I'm seeing it more granularly than class-level and down to the 
 function level.

 After some spitballing, here's something I like:

 ```d
 class E
 {
    restricted int _y;
    restricted(_y) void y(int newY) { _y = newY; }
 }
 ```

 A restricted member variable `_y` can only be accessed in 
 functions explicitly marked `restricted(_y)`. No other member 
 function can access that variable, and therefore neither can 
 anything in the broader module.
This is EXACTLY what I suggested (but I called it hidden int _y and the function UDA sees(_y)). I didn't even received a single response :-(
Jun 20 2022
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 From that perspective, I see massive gaping hole here. I've 
 done a complete 180 on need for further restricting member 
 variable access. But I'm seeing it more granularly than 
 class-level and down to the function level.

 After some spitballing, here's something I like:

 ```d
 class E
 {
    restricted int _y;
    restricted(_y) void y(int newY) { _y = newY; }
 }
 ```
This is very similar in concept to ` system` variables, except instead of a single ` system`/` trusted` attribute pair, you have individual ` trusted`-like attributes for each specific variable. For comparison: ```d class E { system int _y; trusted void y(int newY) { _y = newY; } } ``` I'm not convinced the extra granularity is worth adding an entire new attribute for.
Jun 20 2022
next sibling parent deadalnix <deadalnix gmail.com> writes:
On Monday, 20 June 2022 at 15:49:20 UTC, Paul Backus wrote:
 On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 From that perspective, I see massive gaping hole here. I've 
 done a complete 180 on need for further restricting member 
 variable access. But I'm seeing it more granularly than 
 class-level and down to the function level.

 After some spitballing, here's something I like:

 ```d
 class E
 {
    restricted int _y;
    restricted(_y) void y(int newY) { _y = newY; }
 }
 ```
This is very similar in concept to ` system` variables, except instead of a single ` system`/` trusted` attribute pair, you have individual ` trusted`-like attributes for each specific variable. For comparison: ```d class E { system int _y; trusted void y(int newY) { _y = newY; } } ``` I'm not convinced the extra granularity is worth adding an entire new attribute for.
No. Clearly D has a problem with "a problem => an attribute". But more importantly, the use of data in a class should be strongly cohesive - as in most method should use most of the fields overall. When that's not the case, it's a strong sign that you actually have two class in there, you just bundled them into one. This feature can only be used in a meaningful way in classes that are structured ass backward.
Jun 20 2022
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Monday, 20 June 2022 at 15:49:20 UTC, Paul Backus wrote:

 I'm not convinced the extra granularity is worth adding an 
 entire new attribute for.
My main motivation was the case of having a setter with a contract that serves as a cheap invariant: ```d class Foo { int _x; void x(int newX) in (newX < 1000) { _x = newX; } } ``` If we replace that with an invariant, the problem isn't that the module has access to the protected variable. The problem is that any function in the module that does access the variable is effectively part of the public API, thereby violating the guarantee that the invariant is checked when accessed through the public API. So that is solvable without a new level of protection just by making sure that every write to the variable from within the module triggers the invariant check. The purpose of the function contracts is to validate function input and output, but for a setter like the above it effectively serves as an invariant as long as nothing writes directly to `_x` outside the setter. And from that perspective, it would be nice if there were a way to guarantee that happens both within the module and within the class. So I guess what I'm really after isn't `restricted`, but a targeted invariant, perhaps of the form`invariant(_x) _x < 1000` that only triggers when the protected variable is written to. It just seems overkill to me that an invariant for one member variable is run on calls to every member function. But that also isn't wholly necessary. I can always wrap `_x` in a struct, give it a setter and an invariant/contract, and put that in a separate module. So yeah, `restricted` is pointless. The targeted invariant would be nice, though.
Jun 20 2022
parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 21 June 2022 at 00:33:24 UTC, Mike Parker wrote:
 On Monday, 20 June 2022 at 15:49:20 UTC, Paul Backus wrote:

 I'm not convinced the extra granularity is worth adding an 
 entire new attribute for.
My main motivation was the case of having a setter with a contract that serves as a cheap invariant: ```d class Foo { int _x; void x(int newX) in (newX < 1000) { _x = newX; } } ```
I'm pretty sure x can be encapsulated in some struct here.
Jun 20 2022
parent reply Mike Parker <aldacron gmail.com> writes:
On Tuesday, 21 June 2022 at 01:01:09 UTC, deadalnix wrote:

 I'm pretty sure x can be encapsulated in some struct here.
Yes, I did note that later in the post you just replied to :-) Put it in a struct and then a different module. So `restricted` is absolutely pointless because of that. It's the obvious solution that I overlooked until I read your comment about two classes bundled in one.
Jun 20 2022
parent reply Mike Parker <aldacron gmail.com> writes:
On Tuesday, 21 June 2022 at 01:17:14 UTC, Mike Parker wrote:
 On Tuesday, 21 June 2022 at 01:01:09 UTC, deadalnix wrote:

 I'm pretty sure x can be encapsulated in some struct here.
Yes, I did note that later in the post you just replied to :-) Put it in a struct and then a different module. So `restricted` is absolutely pointless because of that. It's the obvious solution that I overlooked until I read your comment about two classes bundled in one.
That said, spilling class internals out into a separate module is a bit "icky". Targeted invariants would be nice. Not a must have, probably a niche case, but definitely nice to have.
Jun 20 2022
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 21 June 2022 at 01:20:27 UTC, Mike Parker wrote:
 On Tuesday, 21 June 2022 at 01:17:14 UTC, Mike Parker wrote:
 On Tuesday, 21 June 2022 at 01:01:09 UTC, deadalnix wrote:

 I'm pretty sure x can be encapsulated in some struct here.
Yes, I did note that later in the post you just replied to :-) Put it in a struct and then a different module. So `restricted` is absolutely pointless because of that. It's the obvious solution that I overlooked until I read your comment about two classes bundled in one.
That said, spilling class internals out into a separate module is a bit "icky". Targeted invariants would be nice. Not a must have, probably a niche case, but definitely nice to have.
No, you don't spill the struct internal, in fact you don't need to spill anything specific to the struct. What you want to spill is the restricted write mechanism so if goes through a validation step. This can all be done in a template and provided as this for the whole application to use any time someone wants a restricted field. That being said, the invariant really doesn't trigger in a way that is consistent with the other rules of the language, so there is something there. IMO the ivnariant has two problems (one of them I opened a bug repport for, but idk what happened to it): 1/ It need to trigger for anything that touches the class's privates parts, not just members. 2/ Code that trigger the invariant must not call it again down the road, as this tends to cause infinite recursions and/or trigger the invariant mid transform at a time the object might not be valid (and therefore fail the invariant check) even though at no point any external observer can see object in an invalid state.
Jun 20 2022
parent reply The Zealot <zod zod.zod> writes:
On Tuesday, 21 June 2022 at 02:05:22 UTC, deadalnix wrote:
 On Tuesday, 21 June 2022 at 01:20:27 UTC, Mike Parker wrote:
 On Tuesday, 21 June 2022 at 01:17:14 UTC, Mike Parker wrote:
 [...]
That said, spilling class internals out into a separate module is a bit "icky". Targeted invariants would be nice. Not a must have, probably a niche case, but definitely nice to have.
No, you don't spill the struct internal, in fact you don't need to spill anything specific to the struct. What you want to spill is the restricted write mechanism so if goes through a validation step. This can all be done in a template and provided as this for the whole application to use any time someone wants a restricted field. That being said, the invariant really doesn't trigger in a way that is consistent with the other rules of the language, so there is something there. IMO the ivnariant has two problems (one of them I opened a bug repport for, but idk what happened to it): 1/ It need to trigger for anything that touches the class's privates parts, not just members. 2/ Code that trigger the invariant must not call it again down the road, as this tends to cause infinite recursions and/or trigger the invariant mid transform at a time the object might not be valid (and therefore fail the invariant check) even though at no point any external observer can see object in an invalid state.
+1 i absolutely agree with this. if anything, i'd like to see more control over when invariants are actually checked. something like ``` invariant(default) { assert(1 <= day && day <= 31); assert(0 <= hour && hour < 24); } invariant(always) { assert(1 <= sec && sec <= 60); } ```
Jun 21 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 21 June 2022 at 10:36:32 UTC, The Zealot wrote:
 if anything, i'd like to see more control over when invariants 
 are actually checked.

 something like
 ```
 invariant(default)
     {
         assert(1 <= day && day <= 31);
         assert(0 <= hour && hour < 24);
     }
 invariant(always) {
         assert(1 <= sec && sec <= 60);
 }
 ```
You can already do this, just add an or-clause to a compile time boolean constant. ```d assert((!precise_invariant) || (1 <= day && day <= 31)); ``` But the class invariant should only be tested on member-function entry in debug-mode. In release mode the invariant should be assumed to hold on entry and can be used for optimizations (it should still be tested on exit). So this: ```d class always_even { private int x; invariant { assert(x%2==0); } void triple(){ x *= 3; if (x&1) writeln("found one"); } // more code } ``` should become this: ```d class always_even { private int x; tripple(){ // assume(x%2==0) x *= 3; assert(x%2==0); } … } ``` Or even this (with a decent optimizer): ```d class always_even { private int x; tripple(){ // assume(x%2==0) x *= 3; // assert(x%2==0); } … } ``` With invariants turned off, the result will be worse as there is no indication that the lowest bit of x is constant 0: ```d class always_even { private int x; void triple(){ x *= 3; if (x&1) writeln("found one"); } … } ```
Jun 21 2022
parent The Zealot <zod zod.zod> writes:
On Tuesday, 21 June 2022 at 11:20:46 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 21 June 2022 at 10:36:32 UTC, The Zealot wrote:
 if anything, i'd like to see more control over when invariants 
 are actually checked.

 something like
 ```
 invariant(default)
     {
         assert(1 <= day && day <= 31);
         assert(0 <= hour && hour < 24);
     }
 invariant(always) {
         assert(1 <= sec && sec <= 60);
 }
 ```
You can already do this, just add an or-clause to a compile time boolean constant. ```d assert((!precise_invariant) || (1 <= day && day <= 31)); ``` But the class invariant should only be tested on member-function entry in debug-mode. In release mode the invariant should be assumed to hold on entry and can be used for optimizations (it should still be tested on exit). So this: ```d class always_even { private int x; invariant { assert(x%2==0); } void triple(){ x *= 3; if (x&1) writeln("found one"); } // more code } ``` should become this: ```d class always_even { private int x; tripple(){ // assume(x%2==0) x *= 3; assert(x%2==0); } … } ``` Or even this (with a decent optimizer): ```d class always_even { private int x; tripple(){ // assume(x%2==0) x *= 3; // assert(x%2==0); } … } ``` With invariants turned off, the result will be worse as there is no indication that the lowest bit of x is constant 0: ```d class always_even { private int x; void triple(){ x *= 3; if (x&1) writeln("found one"); } … } ```
sorry, i wasn't clear what i meant. i meant add the ability to control when invariants checks are inserted by the compiler. for example a way to specify that you want the invariant checked after each access to any member, as well as "the class invariant should only be tested on member-function entry in debug-mode". but it's mainly a suggestion for performance reasons.
Jun 21 2022
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 21 June 2022 at 01:20:27 UTC, Mike Parker wrote:
 Targeted invariants would be nice. Not a must have, probably a 
 niche case, but definitely nice to have.
The intent is to give the compiler a constraint, so the assumption that the compiler doesn’t have access to the full constraint is the same as assuming that the programmer doesn’t know what he is doing. The right thing to do is to help the programmer and reject such illdpecified constraints. If you specify preconditions/postconditions then the exit check should be considered part of the assumed precondition and the asserted postcondition. If you allow the class invariant to be hidden from the compiler then you mess up the preconditions. Asserts only add information that is redundant and would be removed by a perfect static analysis. If that isn’t possible then either the invariant/assert is badly written or the program is wrong.
Jun 21 2022
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 21 June 2022 at 07:26:50 UTC, Ola Fosheim Grøstad 
wrote:
 If you specify preconditions/postconditions then the exit check 
 should be considered part of the assumed precondition and the 
 asserted postcondition.
The «exit check» that is the class invariant.
Jun 21 2022
prev sibling next sibling parent reply forkit <forkit gmail.com> writes:
On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 I won't rehash the private-to-the-module debate here. I've 
 always looked at it purely in terms of the public vs. private 
 interface. From that perspective, I still don't find the 
 argument that "it breaks encapsulation" a convincing one on the 
 surface.
I don't want to rehash it either, so I'll limit this to one post in this thread. I have a different perspective of that debate, than yours. You (as I understand it) see this private-to-the-module debate, as a debate over whether it breaks encapsulation of the class type. You're argument is no, it doesn't, cause you, the programmer, have complete access and control of the module (in essence, you have encapsulation at your fingers already (the module) so why would you need encapsulation at the class level. My perspective is different: - the programmer in D cannot directly express intent here. - the programmer in D cannot rely on the compiler to catch a violation of that intent. You're argument comes down to: 'you don't need to express that intent, neither do you need to rely on the compiler to catch a violation of that intent, since you have control over the module'. Should you're reasoning only apply to the class type, or should it apply to all areas of programming where you want to express intent, and rely on the compiler to catch a violation of that intent? Thus you can see, how absurd the argument is. I hope.
Jun 20 2022
parent reply The Zealot <zod zod.zod> writes:
On Tuesday, 21 June 2022 at 01:18:38 UTC, forkit wrote:
 On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 [...]
I don't want to rehash it either, so I'll limit this to one post in this thread. [...]
you can already express the intent more clearly by putting the class in either a seperate module, or function scope. we _do_ understand your point, we disagree on it's usefulness and the complexity it adds to the language.
Jun 21 2022
parent bauss <jj_1337 live.dk> writes:
On Tuesday, 21 June 2022 at 10:32:10 UTC, The Zealot wrote:
 On Tuesday, 21 June 2022 at 01:18:38 UTC, forkit wrote:
 On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 [...]
I don't want to rehash it either, so I'll limit this to one post in this thread. [...]
you can already express the intent more clearly by putting the class in either a separate module, or function scope. we _do_ understand your point, we disagree on it's usefulness and the complexity it adds to the language.
What complexity are you talking about? It'll hardly make a difference, if anything adds complexity to the language then it's stuff like dip1000, importC and the whole attribute hell D has bestowed upon itself etc. not anything related to "class private". If you think "class private" is too complex, then arguably programming isn't for you. If you think it adds complexity to the language and/or compiler, then arguably you don't understand how a programming language is developed. There's literally nothing complex about something being private to a class. It's a concept that has existed before D was even a language. Arguably module private is more complex. Not to mention some of those things were just added over night and/or don't work as intended. I'm not against module private, but it sure would be nice to have the opportunity to opt-out sometimes. But that's besides the point of this discussion. I do believe this whole thread wouldn't be necessary if class private really existed. It will solve this issue and many more, it will hardly create any issues that people will not be able to overcome. Every piece of code existing today will work the same way, the only difference will be in future apis.
Jun 21 2022
prev sibling parent reply Max Samukha <maxsamukha gmail.com> writes:
On Monday, 20 June 2022 at 11:04:16 UTC, Mike Parker wrote:
 ```d
 class E
 {
    restricted int _y;
    restricted(_y) void y(int newY) { _y = newY; }
 }
 ```
The "right" way would be to hide the variable in the function's scope. We can hide static variables in this way, but not instance ones. class E { void(int newY) { this int y; // 'this' as storage class will likely be grammatically ambiguous newY = y; } } However, this will only work because currently it is impossible to access variables from the outside at all. If it's changed, the fundamental problem - 'private' not being scope-level - will return. I am actually against any changes to the current situation. Module-level private is *designed* to break encapsulation, so breaking the invariants by module-level functions is expected.
Jun 21 2022
next sibling parent reply Max Samukha <maxsamukha gmail.com> writes:
On Tuesday, 21 June 2022 at 08:37:55 UTC, Max Samukha wrote:

 class E
 {
   void(int newY) {
     this int y; // 'this' as storage class will likely be 
 grammatically ambiguous
     newY = y;
   }
 }
Typo. Should be: ```d class E { void(int newY) { this int y; y = newY; } } ```
Jun 21 2022
parent The Zealot <zod zod.zod> writes:
On Tuesday, 21 June 2022 at 08:40:28 UTC, Max Samukha wrote:
 On Tuesday, 21 June 2022 at 08:37:55 UTC, Max Samukha wrote:

 class E
 {
   void(int newY) {
     this int y; // 'this' as storage class will likely be 
 grammatically ambiguous
     newY = y;
   }
 }
Typo. Should be: ```d class E { void(int newY) { this int y; y = newY; } } ```
this won't solve the 'problem' if the variable has to be accessed by multiple functions. Anyway, i don't think this feature is needed at all. if you run into those problems, you are likely packing too many things into a single class, and you likely should move them to a seperate struct in a seperate module.
Jun 21 2022
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 21 June 2022 at 08:37:55 UTC, Max Samukha wrote:
 I am actually against any changes to the current situation. 
 Module-level private is *designed* to break encapsulation, so 
 breaking the invariants by module-level functions is expected.
Yes, I agree. Either be consistent with the idea that the module is the boundary for encapsulation or not. It is better to give priority to plugging the holes that prevent people from writing code than preventing the compiler from accepting ill-conceived programs. The current D compiler accepts too many programs, but that can be fixed with a linter.
Jun 21 2022
parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 21 June 2022 at 08:55:19 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 21 June 2022 at 08:37:55 UTC, Max Samukha wrote:
 I am actually against any changes to the current situation. 
 Module-level private is *designed* to break encapsulation, so 
 breaking the invariants by module-level functions is expected.
Yes, I agree. Either be consistent with the idea that the module is the boundary for encapsulation or not. It is better to give priority to plugging the holes that prevent people from writing code than preventing the compiler from accepting ill-conceived programs. The current D compiler accepts too many programs, but that can be fixed with a linter.
D will do anything to not have class private.
Jun 21 2022
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 21 June 2022 at 11:06:17 UTC, bauss wrote:
 D will do anything to not have class private.
Yes, but you can do it with UDA + linter. That is a much better approach than getting more complexity into the language (anything more complex than a «hidden» specifier should be rejected)
Jun 21 2022
parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 21 June 2022 at 11:23:36 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 21 June 2022 at 11:06:17 UTC, bauss wrote:
 D will do anything to not have class private.
Yes, but you can do it with UDA + linter. That is a much better approach than getting more complexity into the language (anything more complex than a «hidden» specifier should be rejected)
I don't agree that it's a better approach because then you also have to use a linter and can't just resort to using the compiler. Unless D shipped with a linter that worked with every editor and/or could be put into your build system easily, then I don't think it's a better solution. I'd much rather have the compiler yield an error to me and then fix that, than relying on yet another third party tool.
Jun 21 2022
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 21 June 2022 at 12:18:35 UTC, bauss wrote:
 On Tuesday, 21 June 2022 at 11:23:36 UTC, Ola Fosheim Grøstad 
 wrote:
 (anything more complex than a «hidden» specifier should be 
 rejected)
...
I do agree that it shouldn't be more complex than just a "hidden" keyword tho. Ex. `hidden int x` should be the only thing, nothing more and nothing less. I don't think it's necessary to add anything more complex like controlling who has access etc.
Jun 21 2022
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 21 June 2022 at 12:20:15 UTC, bauss wrote:
 On Tuesday, 21 June 2022 at 12:18:35 UTC, bauss wrote:
 On Tuesday, 21 June 2022 at 11:23:36 UTC, Ola Fosheim Grøstad 
 wrote:
 (anything more complex than a «hidden» specifier should be 
 rejected)
...
I do agree that it shouldn't be more complex than just a "hidden" keyword tho.
Ah, ok. So we agree :)
Jun 21 2022
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Tuesday, 21 June 2022 at 12:18:35 UTC, bauss wrote:
 I'd much rather have the compiler yield an error to me and then 
 fix that, than relying on yet another third party tool.
I'd rather see nothing than more annoying syntax. Since over half of all class attributes should be class-private the syntax has to be short and clean.
Jun 21 2022
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 21 June 2022 at 11:06:17 UTC, bauss wrote:
 D will do anything to not have class private.
To the contrary, it doesn't have that today and is doing nothing. If you want it to do something, you need to justify that it is worth doing. So far, all we got is "This is mandatory as per my definition of OOP", which is not a convincing argument. This is especially not convincing because many people here have been using D for many years, and most of them had a "hu, that's weird" moment when they figured out how private was working. And then figured out that the current behavior is actually much more useful in practice.
Jun 21 2022
next sibling parent bauss <jj_1337 live.dk> writes:
On Tuesday, 21 June 2022 at 12:33:13 UTC, deadalnix wrote:
 On Tuesday, 21 June 2022 at 11:06:17 UTC, bauss wrote:
 D will do anything to not have class private.
To the contrary, it doesn't have that today and is doing nothing. If you want it to do something, you need to justify that it is worth doing. So far, all we got is "This is mandatory as per my definition of OOP", which is not a convincing argument. This is especially not convincing because many people here have been using D for many years, and most of them had a "hu, that's weird" moment when they figured out how private was working. And then figured out that the current behavior is actually much more useful in practice.
Like I've mentioned before I have no problem with module private, I just think it would be a nice-to-have. It's not a deal breaker for me that D doesn't have it, but I do see the value in it. So far I've been doing fine the past decade without and I reckon I will be doing fine regardless of whether it is added.
Jun 21 2022
prev sibling next sibling parent reply Max Samukha <maxsamukha gmail.com> writes:
On Tuesday, 21 June 2022 at 12:33:13 UTC, deadalnix wrote:

 This is especially not convincing because many people here have 
 been using D for many years, and most of them had a "hu, that's 
 weird" moment when they figured out how private was working. 
 And then figured out that the current behavior is actually much 
 more useful in practice.
You don't have any data to substantiate "much more useful", do you?
Jun 21 2022
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 21 June 2022 at 12:53:06 UTC, Max Samukha wrote:
 You don't have any data to substantiate "much more useful", do 
 you?
Unfortunately, this answer did not convince me that something needs to be changed.
Jun 21 2022
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 21 June 2022 at 13:50:35 UTC, deadalnix wrote:
 On Tuesday, 21 June 2022 at 12:53:06 UTC, Max Samukha wrote:
 You don't have any data to substantiate "much more useful", do 
 you?
Unfortunately, this answer did not convince me that something needs to be changed.
Is anyone here actually advocating to redefining private here? I don't see why are you so opposed to optional features, unless there some major drawback that outweighs the benefits that I am unaware of? -Alex
Jun 21 2022
parent Chris Katko <ckatko gmail.com> writes:
On Tuesday, 21 June 2022 at 19:27:10 UTC, 12345swordy wrote:
 On Tuesday, 21 June 2022 at 13:50:35 UTC, deadalnix wrote:
 On Tuesday, 21 June 2022 at 12:53:06 UTC, Max Samukha wrote:
 You don't have any data to substantiate "much more useful", 
 do you?
Unfortunately, this answer did not convince me that something needs to be changed.
Is anyone here actually advocating to redefining private here? I don't see why are you so opposed to optional features, unless there some major drawback that outweighs the benefits that I am unaware of? -Alex
That's my thinking. I really don't care about a war of debates. I need specific tools. I've already illustrated that it's a useful, fundamental construct that I use. - If someone can give me a 10 line patch to DMD that adds it, I'll use that fork from now on. - If someone can give me a optional compiler switch, I'll use that from now on. - If someone can give me a DScanner modified tool that scans for private violations but the compiler ignores it. I'll use that. D isn't my baby. It's my tool. I mean, we might as well flip it around and use these same arguments for the opposite. Why allow modular level private? If you're "git gud" programming, you shouldn't NEED modular private! Modular private is just a crutch for bad programmers that prevents you from expanding existing code, and D is all about expanding code. And 'tossing literally every class into its own file' just to add private is an incredible statement. Oh yeah, let me toss up another 300+ files instead of organizing my project files based on topic and role, I'll just have an extra 300 files all over the place and have to deal with every single class being in its own namespace instead of having any benefit of shared namespaces. And I'm not crapping on whoever suggested it, it's just like we live in different worlds for you to even suggest that. I'm trying to make games here, and I've already illustrated how that's apart of my rapid dev process. Make code work, then make it correct, and private is tool for lopping off sections of code and dealing with them. Maybe private isn't needed for "D is just a shell scripting language" projects. But in a real codebase, private is typesafe documentation. It's a compiler-checked indication of correct usage. You may remember all the bells and whistles of 'best case usage' of your code today, but in two months you won't. If I come off as overly harsh, I apologize, that's just how I communicate and it's not meant as a direct insult.
Jun 21 2022
prev sibling parent reply claptrap <clap trap.com> writes:
On Tuesday, 21 June 2022 at 12:53:06 UTC, Max Samukha wrote:
 On Tuesday, 21 June 2022 at 12:33:13 UTC, deadalnix wrote:

 This is especially not convincing because many people here 
 have been using D for many years, and most of them had a "hu, 
 that's weird" moment when they figured out how private was 
 working. And then figured out that the current behavior is 
 actually much more useful in practice.
You don't have any data to substantiate "much more useful", do you?
Lets be honest there's no data that adding "class private" would prevent bugs or cure cancer. Just a couple of people waving their arms because somebody told them the world aint flat like the good book of OO told them and now they cant cope. The nearest thing to data we have is that the vast majority of experienced D users dont give two hoots about it and the only people who do get upset are the occasional newbie every 6 months or so. Maybe go through github / bugzilla whatever, find some **real** examples of bugs it would have prevented. I think you'll have a tough time, because if it did help prevent bugs more people would be like "oh yeah that would be really useful".
Jun 22 2022
next sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 08:00:41 UTC, claptrap wrote:
 ...
see. i knew there were some anti-OOP in the D community. thanks for the 'data' ;-)
Jun 22 2022
parent reply Sergey <kornburn yandex.ru> writes:
On Wednesday, 22 June 2022 at 08:06:10 UTC, forkit wrote:
 On Wednesday, 22 June 2022 at 08:00:41 UTC, claptrap wrote:
 ...
see. i knew there were some anti-OOP in the D community. thanks for the 'data' ;-)
Concerns about OOP not only in the D-community.. I believe it is the new trend in the last couple of years. For example, chapter Criticism here: https://en.m.wikipedia.org/wiki/Object-oriented_programming
Jun 22 2022
next sibling parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 10:42:00 UTC, Sergey wrote:
 Concerns about OOP not only in the D-community.. I believe it 
 is the new trend in the last couple of years.
 For example, chapter Criticism here:

  https://en.m.wikipedia.org/wiki/Object-oriented_programming
The OO 'paradigm' has been *heavily* critised ever since the term first became used. Any yet, it's one of the most succesful paradigm's to date, having been responsible for some of the biggest software engineering projects in the world. But I'm not for or against any particular paradigm. They all have pros and cons, and are suitable for this situation, and not particulary suitable in some other situation... I prefer multiparadigm actually. But I do believe first and foremost, in using abstract data types, wherever possible - without any regard to a particular 'paradigm'. And I don't means D's interpretation of one (i.e. one that **cannot** declare its own invariants, let alone enforce them). I mean the one defined all the way back in 1974, by Liskov and Zilles. https://dl.acm.org/doi/pdf/10.1145/942572.807045
Jun 22 2022
prev sibling parent reply claptrap <clap trap.com> writes:
On Wednesday, 22 June 2022 at 10:42:00 UTC, Sergey wrote:
 On Wednesday, 22 June 2022 at 08:06:10 UTC, forkit wrote:
 On Wednesday, 22 June 2022 at 08:00:41 UTC, claptrap wrote:
 ...
see. i knew there were some anti-OOP in the D community. thanks for the 'data' ;-)
Concerns about OOP not only in the D-community.. I believe it is the new trend in the last couple of years. For example, chapter Criticism here: https://en.m.wikipedia.org/wiki/Object-oriented_programming
Its Javas fault, it popularised "everything is an object" to the point where it seemed like OOP was touted as the solution to everything. Its not but it an extremely useful tool in a lot of situations. The problem here is that some people think their idea of OOP is the only valid one. And when people dont agree with them they throw their toys out of the pram.
Jun 22 2022
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 11:12:45 UTC, claptrap wrote:
 The problem here is that some people think their idea of OOP is 
 the only valid one. And when people dont agree with them they 
 throw their toys out of the pram.
The problem here is that some people have a poor understanding of modelling, implementation and evolution. D's problem is that this affects D at every level from the compiler implementation, to libraries and language evolution. But encapsulation is not the biggest fish to fry at this moment, so it is a waste of time at this point.
Jun 22 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 11:12:45 UTC, claptrap wrote:
 The problem here is that some people think their idea of OOP is 
 the only valid one. And when people dont agree with them they 
 throw their toys out of the pram.
No. You're confusing terms here. I'm referring to the way in which D butchers the abstract data type concept, by refusing to allow an 'option', so that a class can actually be one. You do not need to be doing OOP, to benefit from abstract data types. Of course, this butchering does have an effect on OOP in D. But that's not the main point here. In fact, you are always using abstract data types, and benefitting from them, regardless of what 'paradigm' you're using. i.e. you cannot put "wtf" into an int. again, the benefits of the abstract data type is well known. here's a lesson, for those that just don't seem to get it: " [imagine a ]string type that guarantees that it will be immutable only if its clients promise not to change it. Then you’d have to check all the places in the code where the string might be used." http://web.mit.edu/6.005/www/fa14/classes/08-abstract-data-types/
Jun 22 2022
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 11:36:52 UTC, forkit wrote:
 Of course, this butchering does have an effect on OOP in D. But 
 that's not the main point here.

 In fact, you are always using abstract data types, and 
 benefitting from them, regardless of what 'paradigm' you're 
 using.
Yes, yes, yes, but many D programmers don't have formal training so they are going by what they read on blogs or their own experience. It should be obvious to anyone that if D's strength is to go from prototyping to shippable products then solid support for evolution is needed. Fine grained encapsulation is absolutely an advantage. That's 100% undeniable. Especially in system level programming. However, if I were to rank what should be focused on, then changing/adding to encapsulation would be at spot 20 or so… Currently the big issue for D is *not loosing focus* and complete what has been started on: 1. competitive memory management 2. safe and trusted 3. completing existing features 4. fixing error handling 5. fixing contracts When all that is done… by all means, look at encapsulation, syntax, etc. But I would predict that the end result, after everyone has added/changed their pet peeve, would be something that would not be D2, it would be D3. So the best option is to either make do with naming-conventions to get ad-hoc class-privacy or implement it as a fork. If you want to do this in a fork then I'll try to help you with locating the spots that need modification. If you complete this on a fork, I'll help you write the DIP for it.
Jun 22 2022
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 08:00:41 UTC, claptrap wrote:
 Maybe go through github / bugzilla whatever, find some **real** 
 examples of bugs it would have prevented. I think you'll have a 
 tough time, because if it did help prevent bugs more people 
 would be like "oh yeah that would be really useful".
It is useful when building your model. That is too obvious a point to argue: Start out by making everything maximally constrained, then loosen up (reluctantly) when you have no other option. The resulting model will be much better than if you just can change things from the outside. The reason for this is that good encapsulated code will produce a higher line count, and most programmers aim for a low line count (subconsciously or deliberately). It is also invaluable when you are dealing with multi-threaded code that does dangerous things related to memory, as such bugs are very difficult to pin-point. It is quite useful to make a class/struct within a class fully encapsulated when you create challenging data structures. E.g. anything lock-free.
Jun 22 2022
next sibling parent reply claptrap <clap trap.com> writes:
On Wednesday, 22 June 2022 at 08:16:26 UTC, Ola Fosheim Grøstad 
wrote:
 It is useful when building your model. That is too obvious a 
 point to argue: Start out by making everything maximally 
 constrained, then loosen up (reluctantly) when you have no 
 other option.
1. Nobody does that. 2. If you dont know up front 99% of what needs to be private or public then you probably ought to give up programming and take up flipping burgers.
Jun 22 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 11:01:27 UTC, claptrap wrote:
 On Wednesday, 22 June 2022 at 08:16:26 UTC, Ola Fosheim Grøstad 
 wrote:
 It is useful when building your model. That is too obvious a 
 point to argue: Start out by making everything maximally 
 constrained, then loosen up (reluctantly) when you have no 
 other option.
1. Nobody does that.
Wrong.
Jun 22 2022
parent reply claptrap <clap trap.com> writes:
On Wednesday, 22 June 2022 at 11:23:47 UTC, Ola Fosheim Grøstad 
wrote:
 On Wednesday, 22 June 2022 at 11:01:27 UTC, claptrap wrote:
 On Wednesday, 22 June 2022 at 08:16:26 UTC, Ola Fosheim 
 Grøstad wrote:
 It is useful when building your model. That is too obvious a 
 point to argue: Start out by making everything maximally 
 constrained, then loosen up (reluctantly) when you have no 
 other option.
1. Nobody does that.
Wrong.
What do you mean by "maximally constrained"?
Jun 22 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 13:08:44 UTC, claptrap wrote:
 On Wednesday, 22 June 2022 at 11:23:47 UTC, Ola Fosheim Grøstad 
 wrote:
 On Wednesday, 22 June 2022 at 11:01:27 UTC, claptrap wrote:
 On Wednesday, 22 June 2022 at 08:16:26 UTC, Ola Fosheim 
 Grøstad wrote:
 It is useful when building your model. That is too obvious a 
 point to argue: Start out by making everything maximally 
 constrained, then loosen up (reluctantly) when you have no 
 other option.
1. Nobody does that.
Wrong.
What do you mean by "maximally constrained"?
It means that you make everything hidden outside the scope, it also means using const, don't apply shared etc etc. Basically, it means you start out providing minimal access both within the module and externally. Then, when you find that yo need to do something that requires direct access (e.g. compare and swap) you give just enough access to enable that. Sometimes you might want to not provide direct access, but create a new accessor-class that is given privileges (e.g. a smart-pointer).
Jun 22 2022
parent claptrap <clap trap.com> writes:
On Wednesday, 22 June 2022 at 13:14:21 UTC, Ola Fosheim Grøstad 
wrote:
 On Wednesday, 22 June 2022 at 13:08:44 UTC, claptrap wrote:
 On Wednesday, 22 June 2022 at 11:23:47 UTC, Ola Fosheim 
 Grøstad wrote:
 On Wednesday, 22 June 2022 at 11:01:27 UTC, claptrap wrote:
 On Wednesday, 22 June 2022 at 08:16:26 UTC, Ola Fosheim 
 Grøstad wrote:
 It is useful when building your model. That is too obvious 
 a point to argue: Start out by making everything maximally 
 constrained, then loosen up (reluctantly) when you have no 
 other option.
1. Nobody does that.
Wrong.
What do you mean by "maximally constrained"?
It means that you make everything hidden outside the scope, it also means using const, don't apply shared etc etc. Basically, it means you start out providing minimal access both within the module and externally.
That's a contradiction, you cant be "make everything hidden outside the scope" and "start with minimal access externally" at the same time. If you mean you start by hiding things unless you are absolutely sure it needs to be in the public API, that makes sense. But if your writing say a file class, you wouldn't start with Open and Close private, that'd just be retarded.
Jun 22 2022
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Wednesday, 22 June 2022 at 08:16:26 UTC, Ola Fosheim Grøstad 
wrote:
 It is useful when building your model. That is too obvious a 
 point to argue: Start out by making everything maximally 
 constrained, then loosen up (reluctantly) when you have no 
 other option. The resulting model will be much better than if 
 you just can change things from the outside. The reason for 
 this is that good encapsulated code will produce a higher line 
 count, and most programmers aim for a low line count 
 (subconsciously or deliberately).
I don't think this is obvious at all. Assuming you and I were extremely intelligent, we wouldn't need any of that? We could keep the whole state of the whole program in our mind and manipulate it with ease. But we aren't. We are just dumb monkeys. So we build abstractions under which we hide part of the complexity of the world we are dealing with and present it through a simplified API. This allow our monkey brain to do more because we can temporarily forget many aspect of the problem at hand. But this comes at a cost. Typically, component A wasn't available from B, so the team in charge of B ends up making a different one that works how so slightly differently rather than depend on A (mind you, they may even now know that A exist at all, or have any sensible way to discover that fact), and now the end result is worse because there are two thing that do A in a slightly different way. Casey Muratori demonstrate that effect using the volume slider in windows here: https://www.youtube.com/watch?v=5IUj1EZwpJY&t=2054s (see timestamp, but the whole presentation is very much worth a watch). So what is the barrier we put in place for our monkey brain when we use private? We state that the private thing is an implementation detail, and that whoever is using our interface shouldn't have to know about it. It leaves space in their brain for something else, which is more important for them to solve the problem at hand - at least, this is the assumption we make. But here, we see the whole bizarre of the current argument: if I want to isolate the user of my code from having to know of the implementation detail of my interface, then it logically follows that they don't belong in the same module, as the module is the unit of abstraction at which implementation happens. The ask is fundamentally inconsistent in its motivations, and this is why the only argument we have for it so far all come in the form of "the holy scripture says so".
Jun 22 2022
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 15:40:35 UTC, deadalnix wrote:
 But we aren't. We are just dumb monkeys. So we build 
 abstractions under which we hide part of the complexity of the 
 world we are dealing with and present it through a simplified 
 API. This allow our monkey brain to do more because we can 
 temporarily forget many aspect of the problem at hand.
You have have many reasons to do encapsulation. One is to separate the specced interface from the implementation. Another one is to reduce complexity in a project that is growing. Yet another one is to document and enforce which parts are subservient to other parts (also within a class). Yet another one is to prevent mistakes when doing dangerous things… etc… However, if you want to support going from an evolved prototype to a solid model then it certainly is very useful to constrain types maximally. In that setting it isn't only an interface-issue, it is a tool for making sure that you tidy up the code base in a gradual, orderly and timely manner. Tighter encapsulation also allows more safe evolution, which is closely related to going from prototype to final model. There is a reason for why Smalltalk was favoured by some for evolutionary development.
 But here, we see the whole bizarre of the current argument: if 
 I want to isolate the user of my code from having to know of 
 the implementation detail of my interface, then it logically 
 follows that they don't belong in the same module, as the 
 module is the unit of abstraction at which implementation 
 happens.
I don't really think "module" is an abstraction, unless you use it as a singleton. It is more like a namespace, for organizing. Usually. You can can use a module for organizing separating layers, in which case it is an abstraction mechanism, but I wouldn't say it generally is used for abstracting.
 The ask is fundamentally inconsistent in its motivations, and 
 this is why the only argument we have for it so far all come in 
 the form of "the holy scripture says so".
No… tigher encapsulation is a tool that gives me more control for a wide variety of reasons.
Jun 22 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 15:40:35 UTC, deadalnix wrote:
 ...
 But here, we see the whole bizarre of the current argument: if 
 I want to isolate the user of my code from having to know of 
 the implementation detail of my interface, then it logically 
 follows that they don't belong in the same module, as the 
 module is the unit of abstraction at which implementation 
 happens.

 The ask is fundamentally inconsistent in its motivations, and 
 this is why the only argument we have for it so far all come in 
 the form of "the holy scripture says so".
Well, programmers are users of their own code. Other programmers are users of other programmers code. This is true now, and it'll be true in the future. A module should be able to handle more than one abstract data type. But it can't. Because the module is THE abstract data type in D. You cannot use a class to represent and abstract data type in D, unless it goes in it's own module. How crazy is that??!!!??!!
Jun 22 2022
parent deadalnix <deadalnix gmail.com> writes:
On Wednesday, 22 June 2022 at 21:25:44 UTC, forkit wrote:
 How crazy is that??!!!??!!
Your inability to present a single real life example is very strong evidence in itself that Max is right.
Jun 22 2022
prev sibling next sibling parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 08:00:41 UTC, claptrap wrote:
 Lets be honest there's no data that adding "class private" 
 would prevent bugs or cure cancer. Just a couple of people 
 waving their arms because somebody told them the world aint 
 flat like the good book of OO told them and now they cant cope.

 The nearest thing to data we have is that the vast majority of 
 experienced D users dont give two hoots about it and the only 
 people who do get upset are the occasional newbie every 6 
 months or so.

 Maybe go through github / bugzilla whatever, find some **real** 
 examples of bugs it would have prevented. I think you'll have a 
 tough time, because if it did help prevent bugs more people 
 would be like "oh yeah that would be really useful".
So your agrument then, is less abstract data type cohesion and greater coupling will improve OO software engineering?
Jun 22 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 08:00:41 UTC, claptrap wrote:
 Lets be honest there's no data that adding "class private" 
 would prevent bugs or cure cancer. Just a couple of people 
 waving their arms because somebody told them the world aint 
 flat like the good book of OO told them and now they cant cope.

 The nearest thing to data we have is that the vast majority of 
 experienced D users dont give two hoots about it and the only 
 people who do get upset are the occasional newbie every 6 
 months or so.

 Maybe go through github / bugzilla whatever, find some **real** 
 examples of bugs it would have prevented. I think you'll have a 
 tough time, because if it did help prevent bugs more people 
 would be like "oh yeah that would be really useful".
Controlling the Use of Information ------------------------------------ "... In this section we discuss the benefits that accrue from this limitation: the programs which result are more modular, and easier to understand, modify, maintain and prove correct." Liskov and Zilles, 1974 https://dl.acm.org/doi/pdf/10.1145/942572.807045
Jun 22 2022
parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 09:33:53 UTC, forkit wrote:

and..

" the final, and perhaps most important, property of a good 
abstract data type is that it preserves its own invariants."

http://web.mit.edu/6.005/www/fa14/classes/08-abstract-data-types/
Jun 22 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Tuesday, 21 June 2022 at 12:33:13 UTC, deadalnix wrote:
 To the contrary, it doesn't have that today and is doing 
 nothing.

 If you want it to do something, you need to justify that it is 
 worth doing.

 So far, all we got is "This is mandatory as per my definition 
 of OOP", which is not a convincing argument.

 This is especially not convincing because many people here have 
 been using D for many years, and most of them had a "hu, that's 
 weird" moment when they figured out how private was working. 
 And then figured out that the current behavior is actually much 
 more useful in practice.
Well, i was going to limit myself to only one post.. but you're comment requires a rebuttal ;-) As an OO programmer for over 20 years (and before that a C/C++ programmer for a short period), I can tell you defintively, that D turning a 'class' type into a 'doWhatEverTheFu%#YouWantWithMe' type, is not acceptable to me, as a programmer. That I need to 'justify' to the D community, as to why I would want an 'option' to declare private members inside my class.. really.. it's a complete joke. It's a even bigger joke, that you can't all see that it's a complete joke. C like procedural programming is fine in D (it's really what it does best). I've been 'playing' with D for what... 6 years now I think....I have a LOT of code in D...but not once have I ever been tempted to do OOP in D. And I never will. Other languages understand the concept of the class type. I mean shit, even Javascript gets it (and that's not even a language! .. but I digress. https://hacks.mozilla.org/2021/06/implementing-private-fields-for-javascript/ You may retort, i know you will. but my point is made, and I need not clarify it any further in this thread.
Jun 21 2022
parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 21 June 2022 at 22:29:13 UTC, forkit wrote:
 Well, i was going to limit myself to only one post.. but you're 
 comment requires a rebuttal ;-)

 As an OO programmer for over 20 years (and before that a C/C++ 
 programmer for a short period), I can tell you defintively, 
 that D turning a 'class' type into a 
 'doWhatEverTheFu%#YouWantWithMe' type, is not acceptable to me, 
 as a programmer.

 That I need to 'justify' to the D community, as to  why I would 
 want an 'option' to declare private members inside my class.. 
 really.. it's a complete joke.

 It's a even bigger joke, that you can't all see that it's a 
 complete joke.

 C like procedural programming is fine in D (it's really what it 
 does best).

 I've been 'playing' with D for what... 6 years now I think....I 
 have a LOT of code in D...but not once have I ever been tempted 
 to do OOP in D. And I never will.

 Other languages understand the concept of the class type.

 I mean shit, even Javascript gets it (and that's not even a 
 language! .. but I digress.

 https://hacks.mozilla.org/2021/06/implementing-private-fields-for-javascript/

 You may retort, i know you will. but my point is made, and I 
 need not clarify it any further in this thread.
Considering you failed to point at any concrete problem caused by that design decision, I'll now have to increase my confidence in the fact that there is none. After, if there were, you'd have stated them.
Jun 21 2022
next sibling parent reply forkit <forkit gmail.com> writes:
On Tuesday, 21 June 2022 at 23:59:03 UTC, deadalnix wrote:
 Considering you failed to point at any concrete problem caused 
 by that design decision, I'll now have to increase my 
 confidence in the fact that there is none.

 After, if there were, you'd have stated them.
Well i had a thread where all these things could have been discussed ;-) One of the 'biggest' selling points of D (certainly for me), was it's syntax being compatible with the syntax of the languages whose developers D was targetting. That was a good decision, and has really paid off, no doubt about it. But as to why Walter then decided to completely change the concept of class, for those same programmers, has, and always will be, a pain point for D - and that continues to be self-evident, from at least 2004. It's much easier to learn new syntax, than changing (and especially being forced to change), a concept that has been the same...for decades... To me, members of a class should be private by default, but you should have the option to make some public (and indeed, you need that option). I'd anticipate that *most* programmers would agree. But the idea that member of a class must be ALWAYS public, is just crazy nonsense! That's not a class type, that's a 'doWhatEverTheFu%$YouWantWithMe' type. If you don't get that, you should not be programming. As Walter has pointed out himself, the one-class-per-module is an unreasonable constraint to impose on a developer. https://forum.dlang.org/post/pr110b$9j5$1 digitalmars.com The only discussion worth having about this, is the technical aspects and consequences of implementing such an option (i.e. should it be soft-private or hard-private, for example.). The discussion as to whether its even worthwhile to allow 'an option' for members of a class to be private, is senseless. Every programmer should already know the benefit of having private class members.
Jun 21 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 00:32:59 UTC, forkit wrote:
 The discussion as to whether its even worthwhile to allow 'an 
 option' for members of a class to be private, is senseless. 
 Every programmer should already know the benefit of having 
 private class members.
Yes, it is indeed true that class private ought to be the default, but in the meanwhile you can use a convention like prefixing with underscore. It is a bit ugly, but not more ugly than «scope private» or «class private».
Jun 21 2022
parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 05:48:22 UTC, Ola Fosheim Grøstad 
wrote:
 On Wednesday, 22 June 2022 at 00:32:59 UTC, forkit wrote:
 The discussion as to whether its even worthwhile to allow 'an 
 option' for members of a class to be private, is senseless. 
 Every programmer should already know the benefit of having 
 private class members.
Yes, it is indeed true that class private ought to be the default, but in the meanwhile you can use a convention like prefixing with underscore. It is a bit ugly, but not more ugly than «scope private» or «class private».
I don't argue that class default should be private. I think most D programmers, would not appreciate this ;-) I'd like it to be sure. I wish it was when D was designed. But I'm not arguing for that now. A future version, maybe, if a majority decide that. As far as defaults are concerned, valid arguments for both module-private and class-private can be presented. The Swift community also undertook discussions related to this, and they decided internal *was* the appropriate default for them. But Swift (rightly) allows programmers to have finer grained control over the class type (and others actually) including fileprivate, But I am unaware of any argument, related to OOP and classes, where not having a language 'option' for declaring a member of a class as private, has provided a benefit to software engineering. I am fully aware of arguments in the other direction however ;-) There is no such thing as a workaround here. Any solution needs to ensure type safety, by (at least) having the compiler statically enforce it. I'd love to get Bjarne Stroustrup, Anders Hejlsberg, Mads Torgersen, James Gosling and Chris Lattner, in a virtual meeting, and ask them this question: "Do you think a class type should be able to declare members to be private?" "Do you think such a declareation should be statically enforced by the compiler?" "What do you think about the D Programming approach, of now giving the programmer that option?" On the last question, I doubt I would get a response. Just a smirk from each of them ;-)
Jun 21 2022
next sibling parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 06:49:01 UTC, forkit wrote:
 "What do you think about the D Programming approach, of now 
 giving the programmer that option?"
oops: "What do you think about the D Programming approach, of NOT giving the programmer that option?"
Jun 21 2022
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 06:49:01 UTC, forkit wrote:
 I don't argue that class default should be private.

 I think most D programmers, would not appreciate this ;-)

 I'd like it to be sure. I wish it was when D was designed.

 But I'm not arguing for that now. A future version, maybe, if a 
 majority decide that.
Well, you can do what I did. Create a fork, add a modified parser that is run on files with a different filename extension (like "file.d3"). Then you can modify your "d3" extension to work as you please. E.g. I made it possible to write ```if 0 ≤ x ≤ 4 {…}``` and such things. It shouldn't be too much work to add things like «hidden» and then find the location where D checks for access-control. This is stuff that is easy to add yourself. Stuff like type system support for memory management is more critical at this point in time. Ask around and I am sure you'll find people who will help you out.
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 07:41:51 UTC, Ola Fosheim Grøstad 
wrote:
 Well, you can do what I did. Create a fork, add a modified 
 parser that is run on files with a different filename extension 
 (like "file.d3").
I do have my own fork (local, not git). I've made some minor changes here and there over time. I only use my fork. I think its the version right before ImportC was added ;-)
 This is stuff that is easy to add yourself.
easy for some ;-)
 Stuff like type system support for memory management is more 
 critical at this point in time.
Even if a DIP were successful, I would not expect it to be prioritised over more pressing matters. Additionally, since its a volunteer commmunity, people will choose what they want to work on - so someone would actually have to 'volunteer' to implement it. I doubt that would be Walter, and in any case, he certainly has enough on his plate... for the forseeble future..... So passing a DIP, and having it implemented, are two **very completely different** things. Let's not conflate them.
Jun 22 2022
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 08:01:12 UTC, forkit wrote:

 I do have my own fork (local, not git).

 I've made some minor changes here and there over time.
Cool! This is one of the more fun aspects of the language.
 I only use my fork. I think its the version right before 
 ImportC was added ;-)
Uhm, yeah, I haven't dared to look at the implications that "ImportC" might have for my fork yet…
Jun 22 2022
prev sibling parent reply Dennis <dkorpel gmail.com> writes:
On Wednesday, 22 June 2022 at 08:01:12 UTC, forkit wrote:
 Additionally, since its a volunteer commmunity, people will 
 choose what they want to work on - so someone would actually 
 have to 'volunteer' to implement it. I doubt that would be 
 Walter, and in any case, he certainly has enough on his 
 plate... for the forseeble future.....
Here you go: https://github.com/dlang/dmd/pull/14238
Jun 22 2022
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 22 June 2022 at 16:16:59 UTC, Dennis wrote:
 [snip]

 Here you go: https://github.com/dlang/dmd/pull/14238
+1
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 18:31:38 UTC, jmh530 wrote:
 On Wednesday, 22 June 2022 at 16:16:59 UTC, Dennis wrote:
 [snip]

 Here you go: https://github.com/dlang/dmd/pull/14238
+1
btw. Great initiative !! Would I be able to do the below with this change? class C { private(this): int x; string str; void secretMethod(){} private: // Do I need some friends ?? public: // interface }
Jun 22 2022
parent reply Dennis <dkorpel gmail.com> writes:
On Wednesday, 22 June 2022 at 22:18:46 UTC, forkit wrote:
 Would I be able to do the below with this change?
Yes
Jun 22 2022
parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 22:23:36 UTC, Dennis wrote:
 On Wednesday, 22 June 2022 at 22:18:46 UTC, forkit wrote:
 Would I be able to do the below with this change?
Yes
woohoo! you've breathed new life into D!!!
Jun 22 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 16:16:59 UTC, Dennis wrote:
 On Wednesday, 22 June 2022 at 08:01:12 UTC, forkit wrote:
 Additionally, since its a volunteer commmunity, people will 
 choose what they want to work on - so someone would actually 
 have to 'volunteer' to implement it. I doubt that would be 
 Walter, and in any case, he certainly has enough on his 
 plate... for the forseeble future.....
Here you go: https://github.com/dlang/dmd/pull/14238
+1 ballsy ;-) maxhaton's comment is interesting "I don't think I've ever actually seen a bug that would've been fixed by this." I refer maxhaton back to the seminal paper on the benefits of abstract data types: Programming with abstract data types - Liskov and Zilles 1974 https://dl.acm.org/doi/pdf/10.1145/942572.807045
Jun 22 2022
next sibling parent reply max haughton <maxhaton gmail.com> writes:
On Wednesday, 22 June 2022 at 21:30:07 UTC, forkit wrote:
 On Wednesday, 22 June 2022 at 16:16:59 UTC, Dennis wrote:
 On Wednesday, 22 June 2022 at 08:01:12 UTC, forkit wrote:
 [...]
Here you go: https://github.com/dlang/dmd/pull/14238
+1 ballsy ;-) maxhaton's comment is interesting "I don't think I've ever actually seen a bug that would've been fixed by this." I refer maxhaton back to the seminal paper on the benefits of abstract data types: Programming with abstract data types - Liskov and Zilles 1974 https://dl.acm.org/doi/pdf/10.1145/942572.807045
To which I ask again: Real example?
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 22:47:11 UTC, max haughton wrote:
 On Wednesday, 22 June 2022 at 21:30:07 UTC, forkit wrote:
 On Wednesday, 22 June 2022 at 16:16:59 UTC, Dennis wrote:
 On Wednesday, 22 June 2022 at 08:01:12 UTC, forkit wrote:
 [...]
Here you go: https://github.com/dlang/dmd/pull/14238
+1 ballsy ;-) maxhaton's comment is interesting "I don't think I've ever actually seen a bug that would've been fixed by this." I refer maxhaton back to the seminal paper on the benefits of abstract data types: Programming with abstract data types - Liskov and Zilles 1974 https://dl.acm.org/doi/pdf/10.1145/942572.807045
To which I ask again: Real example?
I don't get it. You want evidence that abstract data types (types as defined by Liskov and Zilles) contribute to better program modularity? Isn't that self evident? Isn't it also self-evident, that greater modularity leads to programs that can be better understood, modified, maintained, and proved correct? You really need a 'real example' for this? D requires you to think of the D module as being the overarching abstract data type. This results in the kind of design we typically see in D programming. private(this) enables, and encourages, greater module-level modularity, enabling programmers to think more carefully about abstractions within the module itself. private(this) enables the type protection that Liskov and Zilles talk about. Without type protection, you're left with an immutable string that's only immutable as long as those using it (including the programmer), don't try to mutate it. C'mon. I mean really. Are you seriously making an argument, that no benefit can come from 'private(this)'?
Jun 22 2022
parent reply deadalnix <deadalnix gmail.com> writes:
On Wednesday, 22 June 2022 at 23:07:19 UTC, forkit wrote:
 C'mon. I mean really. Are you seriously making an argument, 
 that no benefit can come from 'private(this)'?
forkit, let me introduce you to the concept of burden of proof. See, nobody has to make that case, so you have no need to strawman anyone. On the other hand, **YOU** have to make the case that there is a benefit. Every message in this thread that fail to do so bury the case one foot deeper. Say hello to the moles from me, will you?
Jun 22 2022
next sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 23:12:04 UTC, deadalnix wrote:
 On Wednesday, 22 June 2022 at 23:07:19 UTC, forkit wrote:
 C'mon. I mean really. Are you seriously making an argument, 
 that no benefit can come from 'private(this)'?
forkit, let me introduce you to the concept of burden of proof. See, nobody has to make that case, so you have no need to strawman anyone. On the other hand, **YOU** have to make the case that there is a benefit. Every message in this thread that fail to do so bury the case one foot deeper. Say hello to the moles from me, will you?
This is nonsense. I mean really. The module itself is an abstract data type. The benefits are obvious. Or is your argument, that D should get rid of modules? All 'private(this)' does, is enable the opportunity for greater modularity *within* the module. No evidence is required to back this up. Even a monkey brain should get it.
Jun 22 2022
parent reply deadalnix <deadalnix gmail.com> writes:
On Wednesday, 22 June 2022 at 23:26:11 UTC, forkit wrote:
 No evidence is required to back this up. Even a monkey brain 
 should get it.
Ha, you finally convinced me! Of the fact you are completely unable to come up with a concrete problem solved by this feature.
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 23:37:30 UTC, deadalnix wrote:
 On Wednesday, 22 June 2022 at 23:26:11 UTC, forkit wrote:
 No evidence is required to back this up. Even a monkey brain 
 should get it.
Ha, you finally convinced me! Of the fact you are completely unable to come up with a concrete problem solved by this feature.
I think Stroustrup summed it up (in 1987, and with examples) much better than I can: " Data Abstraction Programming with modules leads to the centralization of all data of a type under the control of a type manager module." https://www.researchgate.net/profile/Bjarne-Stroustrup/publication/221496180_What_is_Object-Oriented_Programming/links/0f3175393334f4f95b000000/What-is-Object-Oriented-Programming.pdf?origin=publication_detail
Jun 22 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 22 June 2022 at 23:51:53 UTC, forkit wrote:
 I think Stroustrup summed it up (in 1987, and with examples) 
 much better than I can:

 " Data Abstraction Programming with modules leads to the 
 centralization of all data of a type under the control of a 
 type manager module."

 https://www.researchgate.net/profile/Bjarne-Stroustrup/publication/221496180_What_is_Object-Oriented_Programming/links/0f3175393334f4f95b000000/What-is-Object-Oriented-Programming.pdf?origin=publication_detail
If you actually look at the quote in context, what Stroustrup is describing is essentially the PIMPL idiom, where the representation of an abstract data type is made entirely opaque to the code using it. This opaqueness is what leads to the shortcomings Stroustrup describes. D's modules do not work like this, and thus do not suffer from those shortcomings. Here is a link to a freely-available PDF of the linked paper, on Stroustrup's own website, for anyone else who would like to read it: https://www.stroustrup.com/whatis.pdf
Jun 22 2022
next sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 00:05:24 UTC, Paul Backus wrote:
 If you actually look at the quote in context, what Stroustrup 
 is describing is essentially the PIMPL idiom, where the 
 representation of an abstract data type is made entirely opaque 
 to the code using it. This opaqueness is what leads to the 
 shortcomings Stroustrup describes.

 D's modules do not work like this, and thus do not suffer from 
 those shortcomings.

 Here is a link to a freely-available PDF of the linked paper, 
 on Stroustrup's own website, for anyone else who would like to 
 read it:

 https://www.stroustrup.com/whatis.pdf
so the paper is actually about the features needed to support the use of proper types, on which OOP techniques depend. the success of both, depend on the design of the types. the design of the types depend on the features available to define those types. data hiding is an important feature in his argument (as are other features). private(this) enables data hiding *within* a module. you now have the tool needed to define an abstract data type *within* a module. you are now longer constrained to one class-per-module. you now have compiler your side, cause it too knows your intent. it can enforce that intent it can use that intent to potentially optimise (inline etc..) it's completely optional to use. I fail to see the downside (providing the syntax fits in well with the rest of the language, and doesn't stand out like a sore thumb). once it's in, people will use it, or not, and all this fuss will be long forgotten....
Jun 22 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 23 June 2022 at 00:20:20 UTC, forkit wrote:
 private(this) enables data hiding *within* a module.

 you now have the tool needed to define an abstract data type 
 *within* a module.
[...]
 I fail to see the downside (providing the syntax fits in well 
 with the rest of the language, and doesn't stand out like a 
 sore thumb).

 once it's in, people will use it, or not, and all this fuss 
 will be long forgotten....
The downside, as with every new language feature, is the cost of implementation and maintenance, plus the opportunity cost of adding new features instead of working on polishing existing ones. I freely acknowledge that private(this) has non-zero upside. It makes the language more expressive. That, by itself, is not enough to justify the addition of a new language feature. In order for private(this) to be added to D, somebody must convince Walter and Atila that the expected upside of it is large enough to outweigh the downside inherent to adding *any* new language feature. This is why people are asking for concrete examples, and are not satisfied with theoretical justifications alone. They don't just want to hear that private(this) *could* be useful; they want to be convinced that it *will* be useful, in practice.
Jun 22 2022
next sibling parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 00:48:13 UTC, Paul Backus wrote:
 ..
I disgree. It will mean D can finally be taken seriously. With private(this), you are not longer constrained to defining a type using the D module mechanism. You can now actually create 'real' user-defined types. As we already now, in D, a type created using the modular mechanism, gets even less suppport than an int type. By that I mean, I use can use an int type throughout my module, and it's invariants will hold. The compiler will make sure of this. The same is not true for user-defined types, because they are enabled using the D module mechansim. That is, they do not own their type, so they cannot declare let alone enforce invariants, since module owns them. Thus any invariants of the user type cannot only be declared and enforced by the module, and not the type. Such types are not user-defined types. With private(this), D turns into a language that supports user-defined types. That's a big deal, IMO.
Jun 22 2022
prev sibling parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 00:48:13 UTC, Paul Backus wrote:
 This is why people are asking for concrete examples, and are 
 not satisfied with theoretical justifications alone. They don't 
 just want to hear that private(this) *could* be useful; they 
 want to be convinced that it *will* be useful, in practice.
I have of course cited numerous papers on this, should anyone 'actually' be interested in learning about it. Anyone that uses abstract data types, should know, already, of the advantage of keeping that types representation 'private'. I should not need to provide evidence for this. Do you know how silly that sounds? 'private(this)' in D, will finally provide the ability to do just that. Of course, if you genuiely believe, that every abstact data type should go in it own module, then the is zero benefit from private(this). Also, if you genuiely believe that programmers do not make mistakes, then there is zero benefit from private(this). btw. The idea of private(this) does not take priority over more pressing issues in D. That is a red-herring argument. If it gets in, it's because someone chose to 'volunteer' their own time, to put it in.
Jun 22 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 00:05:24 UTC, Paul Backus wrote:

Also the argument from Mike, against this idea, was that you have 
access to the module. So why protect yourself from what you have 
access to.

I can use a similar arguement:

by having access to the module, you have the capacity to 'grant' 
yourself access, or not.

if you grant yourself access to use the internals of your type 
outside of that type (but within the same module), you're not 
protected from accidents.

if you don't grant yourself access, you are protected from 
accidents.

the argument that you have access to the module, and accidents 
won't happen, or 'just don't do it', is nonsensical.

any programmer knows, that accidents happen - sometimes far too 
often.

but you have access to the module, so you decide whether you want 
to be protected from accidents or not.

currently, there is one, and only one way to protect yourself in 
D.

that's to put every class in its own module.

even closely related classes -> each into their own module.

every abstract data type you define -> into its own module.

it's just a crazy imposition. no other language I've ever used 
imposes this onto me.
Jun 22 2022
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 23 June 2022 at 00:31:52 UTC, forkit wrote:

 the argument that you have access to the module, and accidents 
 won't happen, or 'just don't do it', is nonsensical.
I never said accidents won't happen. In fact, I'm sure I explicitly called this out as a real potential problem I see with private-to-the-module (especially when multiple people work on it). But I also noted that the same problem exists *within* the class because you can access any private member from any class method. There is absolutely no practical difference here. One of the Effective Java books (IIRC, might have been a different book) pointed this out. If multiple methods modify a private member, then you can't maintain an invariant on that member. Java doesn't have built-in support for invariants like D. The recommended solution? Always modify members through a setter. But according to you, that's a problem because accidents can happen. In D, the `invariant` feature allows you to maintain the invariants of any class from within the class. A class in its a module by itself is fully 100% encapsulated and the invariants are guaranteed. So if you have invariants you don't want violated, then put that class in its own module.
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 00:58:34 UTC, Mike Parker wrote:
 On Thursday, 23 June 2022 at 00:31:52 UTC, forkit wrote:

 the argument that you have access to the module, and accidents 
 won't happen, or 'just don't do it', is nonsensical.
I never said accidents won't happen. In fact, I'm sure I explicitly called this out as a real potential problem I see with private-to-the-module (especially when multiple people work on it). But I also noted that the same problem exists *within* the class because you can access any private member from any class method. There is absolutely no practical difference here.
It's just a matter of scale. Big long classes, and you're back in the same problem area. But with private(this), you can put small, closely related, user-defined types, in the same module, and never have to worry about mistakes. Not ever. Not by you, and not by anyone else.
 One of the Effective Java books (IIRC, might have been a 
 different book) pointed this out. If multiple methods modify a 
 private member, then you can't maintain an invariant on that 
 member. Java doesn't have built-in support for invariants like 
 D. The recommended solution? Always modify members through a 
 setter. But according to you, that's a problem because 
 accidents can happen.
It's a matter of scale. The smaller the scope, the easier it is to identify 'mistakes'. I'd rather find that mistake in the definition of the class, then on line 1050 down the module, where some 'free' function is doing something I didn't anticipate (i.e. a mistake).
 In D, the `invariant` feature allows you to maintain the 
 invariants of any class from within the class. A class in its a 
 module by itself is fully 100% encapsulated and the invariants 
 are guaranteed. So if you have invariants you don't want 
 violated, then put that class in its own module.
Walter is already on the record as saying this is an unreasonable constraint to impose. Has he changed his view?
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 01:13:22 UTC, forkit wrote:
 ...
 In D, the `invariant` feature allows you to maintain the 
 invariants of any class from within the class.
 ..
On re-reading that part again, I'm confused as to what it means. What is this 'invariant' feature you mention?
Jun 22 2022
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 23 June 2022 at 01:19:11 UTC, forkit wrote:
 On Thursday, 23 June 2022 at 01:13:22 UTC, forkit wrote:
 ...
 In D, the `invariant` feature allows you to maintain the 
 invariants of any class from within the class.
 ..
On re-reading that part again, I'm confused as to what it means. What is this 'invariant' feature you mention?
https://dlang.org/spec/class.html#invariants A class in its own module can fully maintain its invariants, even when multiple methods modify a variable. Every function call is bookended with the invariant check. There's a hole in module scope in that we treat modules as part of the aggregate's private API, but not as part of the public API. A new level of protection wouldn't fully plug that hole, but running invariant checks on access to private member variables from within the module would. This whole discussion has led me to the opinion that if a module is part of the private API, then we ought to be treating it as part of the public API in terms of invariant and synchronized.
Jun 22 2022
next sibling parent deadalnix <deadalnix gmail.com> writes:
On Thursday, 23 June 2022 at 01:27:23 UTC, Mike Parker wrote:
 On Thursday, 23 June 2022 at 01:19:11 UTC, forkit wrote:
 On Thursday, 23 June 2022 at 01:13:22 UTC, forkit wrote:
 ...
 In D, the `invariant` feature allows you to maintain the 
 invariants of any class from within the class.
 ..
On re-reading that part again, I'm confused as to what it means. What is this 'invariant' feature you mention?
https://dlang.org/spec/class.html#invariants A class in its own module can fully maintain its invariants, even when multiple methods modify a variable. Every function call is bookended with the invariant check.
So obviously, the problem here is that the scoping for invariant check is wrong. But you already started a thread about this, so I assume you understand this fairly well.
Jun 22 2022
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 23 June 2022 at 01:27:23 UTC, Mike Parker wrote:
 A class in its own module can fully maintain its invariants, 
 even when multiple methods modify a variable. Every function 
 call is bookended with the invariant check.

 There's a hole in module scope in that we treat modules as part 
 of the aggregate's private API, but not as part of the public 
 API. A new level of protection wouldn't fully plug that hole, 
 but running invariant checks on access to private member 
 variables from within the module would.

 This whole discussion has led me to the opinion that if a 
 module is part of the private API, then we ought to be treating 
 it as part of the public API in terms of invariant and 
 synchronized.
Your proposal would lead to the following situation: struct EvenNumber { private int n; invariant (n & 1 == 0); this(int n) { this.n = n; } void addTwoMethod() { this.n++; this.n++; } // ok } void addTwoUFCS(ref EvenNumber this_) { this_.n++; this_.n++; // error - violates invariant } IMO the correct way to view this is that code in the same module as a class is part of the class's implementation, just as much as code in the actual class body. (Or if you prefer, they are both part of the module's implementation, since the module is the fundamental unit of decomposition here, not the class.) Note that sometimes, one is actually required to implement methods as UFCS functions rather than actual aggregate members--for example, to work around issue 5710 [1], or if one wants to write a struct method that takes its "this" argument by value instead of by reference. [1] https://issues.dlang.org/show_bug.cgi?id=5710
Jun 22 2022
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 23 June 2022 at 01:45:22 UTC, Paul Backus wrote:

 Your proposal would lead to the following situation:

     struct EvenNumber
     {
         private int n;
         invariant (n & 1 == 0);

         this(int n) { this.n = n; }

         void addTwoMethod() { this.n++; this.n++; } // ok
     }

     void addTwoUFCS(ref EvenNumber this_)
     {
         this_.n++; this_.n++; // error - violates invariant
     }
I could live with that particular inconsistency. The bigger downside I see is that you'd potentially have multiple invariant checks for the same class on a single function call. And whether that's acceptable depends on how common this is in practice.
 IMO the correct way to view this is that code in the same 
 module as a class is part of the class's implementation, just 
 as much as code in the actual class body. (Or if you prefer, 
 they are both part of the module's implementation, since the 
 module is the fundamental unit of decomposition here, not the 
 class.)
As long as the invariant checks only run on those functions that actually touch a private member. There would potentially be checks for multiple classes running before and after each function call, so doing it on every function call in the module is overkill. And that would also have to include any public member functions of any classes that access any private members of other classes in the same module. It seems more complex to implement than just doing a rewrite to getters/setters. An even simpler option would be to disallow access to any private members in a module on classes that have invariants. Not something I'd advocate, but a possibility.
Jun 22 2022
parent The Zealot <zod zod.zod> writes:
On Thursday, 23 June 2022 at 03:10:46 UTC, Mike Parker wrote:
 On Thursday, 23 June 2022 at 01:45:22 UTC, Paul Backus wrote:

 Your proposal would lead to the following situation:

     struct EvenNumber
     {
         private int n;
         invariant (n & 1 == 0);

         this(int n) { this.n = n; }

         void addTwoMethod() { this.n++; this.n++; } // ok
     }

     void addTwoUFCS(ref EvenNumber this_)
     {
         this_.n++; this_.n++; // error - violates invariant
     }
I could live with that particular inconsistency. The bigger downside I see is that you'd potentially have multiple invariant checks for the same class on a single function call. And whether that's acceptable depends on how common this is in practice.
 IMO the correct way to view this is that code in the same 
 module as a class is part of the class's implementation, just 
 as much as code in the actual class body. (Or if you prefer, 
 they are both part of the module's implementation, since the 
 module is the fundamental unit of decomposition here, not the 
 class.)
As long as the invariant checks only run on those functions that actually touch a private member. There would potentially be checks for multiple classes running before and after each function call, so doing it on every function call in the module is overkill. And that would also have to include any public member functions of any classes that access any private members of other classes in the same module. It seems more complex to implement than just doing a rewrite to getters/setters. An even simpler option would be to disallow access to any private members in a module on classes that have invariants. Not something I'd advocate, but a possibility.
Another idea would be to force the programmer to specify _when_ the invariant checks happen. : ``` struct EvenNumber { private int n; invariant (n & 1 == 0); this(int n) { this.n = n; } void addTwoMethod() { this.n++; this.n++; } // ok } void addTwoUFCS(ref EvenNumber this_) { invariant(enter) { // invariant is checked here this_.n++; this_.n++; } invariant(exit) { this_.n++; this_.n++; } // invariant is checked here invariant(access) { this_.n++; // invariant is checked here this_.n++; // invariant is checked here } } ```
Jun 23 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 01:27:23 UTC, Mike Parker wrote:
 https://dlang.org/spec/class.html#invariants

 A class in its own module can fully maintain its invariants, 
 even when multiple methods modify a variable. Every function 
 call is bookended with the invariant check.

 ...
Well, the 'invariant' statement in D, is interesting, but no replacement for strong typing. I'm comfortable in saying, that a generally accepted central principle of good design, for a strongly typed abstract object, is that it can protect, isolate, limit access to (.. whatever terms you wanna use) its internal representation, and thereby ensure any actions on it are limited to the actions that **it** defines. An int type, is a simple, but clear example of this principle. I cannot put "wtf" into an int. private(this) .. (or whatever syntax people are comfortable with), would ensure I can declare 'my own' strongly typed abstract object. I now longer have to put that type in its own module, just to pretend its strongly typed. My degree was in psychology, not computer science. But surely they teach this concept in computer science? Or is this all new to D users?
Jun 22 2022
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 23 June 2022 at 03:55:00 UTC, forkit wrote:

 Or is this all new to D users?
I was a Java programmer before I was a D programmer. I understand all of the OOP principles you've been bringing up in this discussion, as I'm sure everyone else does. What I'm arguing is that those principles still hold in D. The difference between D and Java (or similar) is that in D, the boundary is at the module level, not the class level. Everything in the module is part of the private API. We've just expanded the definition of private API from "inside the class" to inside the module. Your types are still as strong, still as encapsulated, via the public API (outside of the module). In Java, anything that shouldn't touch the private API of a class shouldn't be part of that class. In D, anything that shouldn't touch the private API of a class shouldn't be in the same module as that class. How are the two concepts any different? This is what you've got to show. What is the *practical* problem that private-to-the-module causes that wouldn't be true if we had private-to-the-class (i.e., what can go wrong with the module as part of the private API that wouldn't go wrong if the same thing were done inside the class). Yes, there's a problem in that invariants and mutex locks can be bypassed, but that's not a problem with the private API. The private API is allowed to touch that stuff. It's a problem because it violates the public API, i.e., external calls to module functions bypass the invariant and the mutex lock. That's a bug that can be fixed without a new protection attribute. Arguments that encapsulation is broken in D because of private-to-the-module are purely ideological without a concrete example of a problem a new protection attribute would prevent. Yes, it's true that the class boundary is violated in the module. But because the module is part of the private API, that doesn't matter one bit.
Jun 22 2022
next sibling parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 04:34:03 UTC, Mike Parker wrote:
 On Thursday, 23 June 2022 at 03:55:00 UTC, forkit wrote:

 Or is this all new to D users?
I was a Java programmer before I was a D programmer. I understand all of the OOP principles you've been bringing up in this discussion, as I'm sure everyone else does. What I'm arguing is that those principles still hold in D. The difference between D and Java (or similar) is that in D, the boundary is at the module level, not the class level. Everything in the module is part of the private API. We've just expanded the definition of private API from "inside the class" to inside the module. Your types are still as strong, still as encapsulated, via the public API (outside of the module).
Well, I'm not sure strong is the right word here. I think you mean, strongly enforced by something other than the type. That is not the same as a strong type.
 Arguments that encapsulation is broken in D because of 
 private-to-the-module are purely ideological without a concrete 
 example of a problem a new protection attribute would prevent. 
 Yes, it's true that the class boundary is violated in the 
 module. But because the module is part of the private API, that 
 doesn't matter one bit.
so, just to do simulate a strong type in D, I have to take this tiny little base class and put it in its own module? Woohoo! It's 2022, and i can simulate a strong type in D. So the problem here, since so many don't get it, is that I can only simulate a strong type in D, by putting that type in its own module. That IS the problem. That is not the basis on which a language can claim to support OOP using classes! module test; safe: class Base { private: int x = 100; public: int getX(){ return this.x;} } class Derived : Base { } unittest { import std; Derived d = new Derived(); writeln(d.x); // oops. mistake. // can't rely on the compiler here, // its hasn't a clue what's going on. writeln(d.getX()); // using the public interface is cool. }
Jun 22 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 04:34:03 UTC, Mike Parker wrote:
 ...
 Yes, it's true that the class boundary is violated in the 
 module.
Oh. you just said it better than I ;-) 'the class boundary is violated in the module'. D's claim to fame. I'm sure that will attract all those millions of OOP out there. They'll be banging down your door to get in, so they can start using D.
 But because the module is part of the private API, that doesn't 
 matter one bit.
Umm. If it's not in the api of my class, then it shouldn't be in the api of my class. Don't force your own api into my class. On what basis should i accept that? Not only has the D module redefined the concept of a strong abstract data type, it's also trying to redefine the very basis of OOP (a strong abstract data type). btw. Why won't the module let me put "wtf" into an int? Oh. cause built in types are strongly typed. the compiler ensures its invariants are upheld. but your user-defined types do not get that privledge in D. You can call it ideological, philosophical, or whatever, but I just cannot accept it. A language that I use (outside of playing with it), must support the concept of a strong abstract data type. offering of a constraining workaround just to simulate one, is absurd.
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 05:09:17 UTC, forkit wrote:

gather around kids...

This is how encapsulation is achieved.

Each object is in charge of its own state.

Each object keeps that state private.

Other objects don’t have direct access to this state.

Instead, they can only call a list of public functions — called 
methods.

Now if your using the D programming langauge, this isn't the 
entire story. The rest of that story is in that big, black, scary 
book on the top shelf. In that book, you can make a cat bark, if 
you want. But we won't go there. It's too scary!

"How to explain object-oriented programming concepts to a 
6-year-old"

https://www.freecodecamp.org/news/object-oriented-programming-concepts-21bb035f7260/
Jun 22 2022
parent reply Jordan Wilson <wilsonjord gmail.com> writes:
On Thursday, 23 June 2022 at 05:22:26 UTC, forkit wrote:
 On Thursday, 23 June 2022 at 05:09:17 UTC, forkit wrote:

 gather around kids...

 This is how encapsulation is achieved.

 Each object is in charge of its own state.

 Each object keeps that state private.

 Other objects don’t have direct access to this state.

 Instead, they can only call a list of public functions — called 
 methods.

 Now if your using the D programming langauge, this isn't the 
 entire story. The rest of that story is in that big, black, 
 scary book on the top shelf. In that book, you can make a cat 
 bark, if you want. But we won't go there. It's too scary!

 "How to explain object-oriented programming concepts to a 
 6-year-old"

 https://www.freecodecamp.org/news/object-oriented-programming-concepts-21bb035f7260/
Well, you what they say, if first you don't succeed (with copy/pasted appeals to authority), then try, try again (this time, with extra condescension).
Jun 22 2022
next sibling parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 06:55:30 UTC, Jordan Wilson wrote:
 ..
 Well, you what they say, if first you don't succeed (with 
 copy/pasted appeals to authority), then try, try again (this 
 time, with extra condescension).
really. that's what they say? you mean, i did it right?
Jun 23 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 06:55:30 UTC, Jordan Wilson wrote:
 ..
 Well, you what they say, if first you don't succeed (with 
 copy/pasted appeals to authority), then try, try again (this 
 time, with extra condescension).
btw. I noticed you said NOTHING, ABSOLUTELY NOTHING, when the condescension was being directed towards me. I guess we know which side of the debate your on.
Jun 23 2022
parent Jordan Wilson <wilsonjord gmail.com> writes:
On Thursday, 23 June 2022 at 07:04:55 UTC, forkit wrote:
 On Thursday, 23 June 2022 at 06:55:30 UTC, Jordan Wilson wrote:
 ..
 Well, you what they say, if first you don't succeed (with 
 copy/pasted appeals to authority), then try, try again (this 
 time, with extra condescension).
btw. I noticed you said NOTHING, ABSOLUTELY NOTHING, when the condescension was being directed towards me.
The last 60 messages to the General forums, almost 50% are from yourself. If I've picked up on certain undesirable tones from your messages, it's simply due to the quantity presented.
 I guess we know which side of the debate your on.
No need to guess. If private(scope) was introduced to the D language, I'd go "cool". If you asked if I supported such a DIP, I'd go "sure". If others disagreed with me, what I wouldn't do imply that those that disagree: - are kids - are not 'actually' interested in learning about it (i.e. willfully ignorant) - make grand sweeping statements like "D can finally be taken seriously [when this feature is implemented]" (the list could go on) Look, I commend you wanting D to be better; I cannot commend how you have been trying to achieve this. Jordan
Jun 23 2022
prev sibling parent reply Dom Disc <dominikus scherkl.de> writes:
On Thursday, 23 June 2022 at 03:55:00 UTC, forkit wrote:
 On Thursday, 23 June 2022 at 01:27:23 UTC, Mike Parker wrote:
 Well, the 'invariant' statement in D, is interesting, but no 
 replacement for strong typing.
If you accept that one module should only contain one class and it's friends, then it is strong typed. Hey, even the OS support its encapsulation: you can make the file read only. What better encapsulation do you want?
 I cannot put "wtf" into an int.
Yes. Because from user perspective it is encapsulated. But if you own the module where int is implemented, of course you can add "wtf" there! If you want your class to be encapsulated the same way, put it in its own module and make it read only. You can be sure nobody can add "wtf" to your class, just like with int.
 I no longer have to put that type in its own module
But this is just coding style. And here you see the cost of private(this). As of now, everybody reading a D source file can be sure everything in a module belongs together. Because a special coding style is enforced on the developers by the language. With private(this) that assumption no longer holds. You can conflate everything in one file. Just because now you have that option. Can you see that it has some negative impact? It's benefit has to outweight that impact, or it is not worth adding it. And many people in this forum think it doesn't. That is why they insist on you presenting evidence of the benefit. Coding style guides are good. It makes a language much more readable if everybody is enforced to do one thing always the same way. Of course they reduce your freedom. If you were a poet, that would be really bad. But as a programmer do you need that freedom? Isn't it sufficient, that there *is* one way to do something?
Jun 23 2022
parent reply Max Samukha <maxsamukha gmail.com> writes:
On Thursday, 23 June 2022 at 09:44:29 UTC, Dom Disc wrote:
 If you want your class to be encapsulated the same way, put it 
 in its own module and make it read only.
...which resulted in unnatural duplicate names in symbol paths everywhere. Look at Tango, the glorious alternative D standard library, which tried to be classic Java-style OOP. Many (most?) classes there have paths like 'tango.io.device.Device.Device' (https://github.com/SiegeLord/Tango-D2/blob/d2port/tango/io/device/Device.d). (yes, I know that in today's D you can use 'package.d' as a kludge to work around this).
Jun 23 2022
parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Thursday, 23 June 2022 at 10:50:30 UTC, Max Samukha wrote:
 On Thursday, 23 June 2022 at 09:44:29 UTC, Dom Disc wrote:
 If you want your class to be encapsulated the same way, put it 
 in its own module and make it read only.
...which resulted in unnatural duplicate names in symbol paths everywhere. Look at Tango, the glorious alternative D standard library, which tried to be classic Java-style OOP. Many (most?) classes there have paths like 'tango.io.device.Device.Device' (https://github.com/SiegeLord/Tango-D2/blob/d2port/tango/io/device/Device.d). (yes, I know that in today's D you can use 'package.d' as a kludge to work around this).
Imho package.d is not a kludge. Such approach is taken in typescript/javascript for example.
Jun 23 2022
parent Max Samukha <maxsamukha gmail.com> writes:
On Thursday, 23 June 2022 at 10:55:29 UTC, Alexandru Ermicioi 
wrote:

 Imho package.d is not a kludge. Such approach is taken in 
 typescript/javascript for example.
It is useful when you need to split a module into multiple submodules for other reasons than class-level encapsulation. In Javascript, there had been the '_' naming convention until it acquired proper class-level private https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/P ivate_class_fields. Typescript has class-level private https://www.typescriptlang.org/docs/handbook/2/classes.html#private
Jun 23 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 23:12:04 UTC, deadalnix wrote:
 On Wednesday, 22 June 2022 at 23:07:19 UTC, forkit wrote:
 C'mon. I mean really. Are you seriously making an argument, 
 that no benefit can come from 'private(this)'?
forkit, let me introduce you to the concept of burden of proof. See, nobody has to make that case, so you have no need to strawman anyone. On the other hand, **YOU** have to make the case that there is a benefit. Every message in this thread that fail to do so bury the case one foot deeper. Say hello to the moles from me, will you?
google scholar. search for: "benefits of program modularity" I'm sure you'll find enough material to keep you busy for a long time.... hopefully ;-)
Jun 22 2022
parent deadalnix <deadalnix gmail.com> writes:
On Wednesday, 22 June 2022 at 23:35:01 UTC, forkit wrote:
 google scholar.

 search for: "benefits of program **modul**arity"

 I'm sure you'll find enough material to keep you busy for a 
 long time.... hopefully ;-)
Emphasis is mine.
Jun 22 2022
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Wednesday, 22 June 2022 at 21:30:07 UTC, forkit wrote:
 I refer maxhaton back to the seminal paper on the benefits of 
 abstract data types:

 Programming with abstract data types - Liskov and Zilles 1974

 https://dl.acm.org/doi/pdf/10.1145/942572.807045
I wish you understood that every comment that you make where you fail to present any concrete instance of the problem caused weakens your case. Assuming the people you are talking to are not well versed in the concept of asbtract data types is somewhat amusing, but I'm afraid, also playing against your case.
Jun 22 2022
next sibling parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 23:08:38 UTC, deadalnix wrote:
 On Wednesday, 22 June 2022 at 21:30:07 UTC, forkit wrote:
 I refer maxhaton back to the seminal paper on the benefits of 
 abstract data types:

 Programming with abstract data types - Liskov and Zilles 1974

 https://dl.acm.org/doi/pdf/10.1145/942572.807045
I wish you understood that every comment that you make where you fail to present any concrete instance of the problem caused weakens your case. Assuming the people you are talking to are not well versed in the concept of asbtract data types is somewhat amusing, but I'm afraid, also playing against your case.
But my case is simple. Really, really, really simple. private(this) enables you to create an actual abstract data type, **within** the module. That is, a type that "may be operated upon by the operations which define its abstract type". Without private(this), it is just not possible to do this. In essence, what can currently do in D, within a module, is declare an immutable string type that is immutable as long as those using it (elsewhere in the module) don't mutate it. That is not an abstract data type. The benefits that arise from being able to use a real, enforceable, abstract data type *within* a module, are that it enables code within the module, to become more modular. Programmers now have the tool to make this possible! Only good things can comes from this. There is no downside to finer grained modularity, within a module. If there is, can you provide a real world example please.
Jun 22 2022
prev sibling parent reply user1234 <user1234 12.de> writes:
On Wednesday, 22 June 2022 at 23:08:38 UTC, deadalnix wrote:
 On Wednesday, 22 June 2022 at 21:30:07 UTC, forkit wrote:
 I refer maxhaton back to the seminal paper on the benefits of 
 abstract data types:

 Programming with abstract data types - Liskov and Zilles 1974

 https://dl.acm.org/doi/pdf/10.1145/942572.807045
I wish you understood that every comment that you make where you fail to present any concrete instance of the problem caused weakens your case. Assuming the people you are talking to are not well versed in the concept of asbtract data types is somewhat amusing, but I'm afraid, also playing against your case.
to be fair, I think that, to any example presented here, the answer will be "put the aggregate declaration in its own module". But let's try something simple: ```d struct VLA { private: void* ptr; size_t length; public: void setLength(size_t value); } struct Other { VLA vla; void imBad() { length += 1; // now I may have faults or not when reading the vla } } ``` It's about being strict with yourself. What if I'm not really good, make stupid mistakes ? Now I have a security barrier, I can use `private(this)`, the compiler helps me with an error.
Jun 22 2022
next sibling parent user1234 <user1234 12.de> writes:
On Wednesday, 22 June 2022 at 23:31:28 UTC, user1234 wrote:

oh no... `vla.length +=` obviously.
Jun 22 2022
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Wednesday, 22 June 2022 at 23:31:28 UTC, user1234 wrote:
 ```d
 struct VLA {
 private:
     void* ptr;
     size_t length;
 public:
     void setLength(size_t value);
 }

 struct Other {
     VLA vla;
     void imBad() {
         vla.length += 1; // now I may have faults or not when 
 reading the vla
     }
 }
 ```
This is a good starting point. Yes, Other will be able to manipulate VLA's innard in this exemple. Now there are two questions that immediately come to mind: 1/ Should it be able to? From this limited example, it's hard to tell, but there is no need to be pedantic so we'll assume that yes it does. You'll note that this is not obvious per so, Other might be a view on the VLA for instance. 2/ If 1/ is true, then do they really belong in the same module? I think 2/ is the question that is being skipped there, because the very characteristic of a module is to be the place where all the element it contains are implemented. If it is capital that Other is not exposed to the innard of VLA, then is it hard to defend that implementing them both together in the same place is the right design choice.
 It's about being strict with yourself. What if I'm not really 
 good, make stupid mistakes ? Now I have a security barrier, I 
 can use `private(this)`, the compiler helps me with an error.
While I do indeed believe that it is good to be strict with yourself, I do not believe the arguments extends to private(this) based on the sample provided. In fact, I had to correct said sample to add an explicit reference to `vla.length` instead of just `length`. The compiler is already helping you avoiding accessing the innard of another object by mistake, it has to be explicit. The proof is in the pudding, the code had to be modified for it to be explicit.
Jun 22 2022
parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 23:48:22 UTC, deadalnix wrote:
 ```
This is a good starting point. Yes, Other will be able to manipulate VLA's innard in this exemple. Now there are two questions that immediately come to mind: 1/ Should it be able to? From this limited example, it's hard to tell, but there is no need to be pedantic so we'll assume that yes it does. You'll note that this is not obvious per so, Other might be a view on the VLA for instance. 2/ If 1/ is true, then do they really belong in the same module? I think 2/ is the question that is being skipped there, because the very characteristic of a module is to be the place where all the element it contains are implemented. If it is capital that Other is not exposed to the innard of VLA, then is it hard to defend that implementing them both together in the same place is the right design choice.
shouldn't 'what goes in a module' be the choice of the programmer? why does it have to be something enforced on the programmer, by the language? the problem with the D module, is that enforces on all programmers, that IT is THE MASTER abstract data type to rule them all, and all others shall bow to it. Sorry, but no! My types will NOT bow. In fact, not even an int in D bows to that demand. Why should my types?
Jun 22 2022
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 22 June 2022 at 23:31:28 UTC, user1234 wrote:
 to be fair, I think that, to any example presented here, the 
 answer will be "put the aggregate declaration in its own 
 module". But let's try something simple:

 ```d
 struct VLA {
 private:
     void* ptr;
     size_t length;
 public:
     void setLength(size_t value);
 }

 struct Other {
     VLA vla;
     void imBad() {
         length += 1; // now I may have faults or not when 
 reading the vla
     }
 }
 ```

 It's about being strict with yourself. What if I'm not really 
 good, make stupid mistakes ? Now I have a security barrier, I 
 can use `private(this)`, the compiler helps me with an error.
As you point out, you can already create such a security barrier by splitting the code into separate modules. Nobody denies that the ability to create more fine-grained security barriers has *some* utility in *some* situations. The question is, does it provide *enough* utility in *enough* situations to justify the addition of a new language feature? Personally, I like to write small modules, and would probably put my VLA definition in its own module even if `private(this)` were available. So `private(this)` would not actually bring me any benefit in this situation. (Also, because VLA's invariant is memory-safety related, I would get an additional security barrier by making its private members into [` system` variables][1]. So the extra protection provided by `private(this)` would only be relevant in ` system` or ` trusted` code--which can bypass access controls anyway.) [1]: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1035.md
Jun 22 2022
next sibling parent forkit <forkit gmail.com> writes:
On Wednesday, 22 June 2022 at 23:55:17 UTC, Paul Backus wrote:
 As you point out, you can already create such a security 
 barrier by splitting the code into separate modules.

 Nobody denies that the ability to create more fine-grained 
 security barriers has *some* utility in *some* situations. The 
 question is, does it provide *enough* utility in *enough* 
 situations to justify the addition of a new language feature?

 Personally, I like to write small modules, and would probably 
 put my VLA definition in its own module even if `private(this)` 
 were available. So `private(this)` would not actually bring me 
 any benefit in this situation.
Is it a security barrier? I think of it more as an encapsulation barrier. Like my wall around my house. It's only secure as long as nobody tries to knock it down. Also, let's not forget about 'choice' here. the use of private(this) is the choice of the designer. always! if it benefits you, choose to use it. if it doesn't, don't use it. but currently, D provides NO CHOICE, other than to put every class in its own module, so that it can be treated as a 'defacto' abstract data type. Walter is already on the record as saying this is not an appropriate contraint to put on programmers.
Jun 22 2022
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Wednesday, 22 June 2022 at 23:55:17 UTC, Paul Backus wrote:
 Nobody denies that the ability to create more fine-grained 
 security barriers has *some* utility in *some* situations. The 
 question is, does it provide *enough* utility in *enough* 
 situations to justify the addition of a new language feature?
Stronger typing is desirable in complex performance oriented system level programming. This is the biggest weakness of C. Modules are clearly weaker than class/struct level protection. Weaker typing is not better in this context. But «private(this)» is inconsistent and ugly. Other languages being ugly is not a good excuse. Most fields should be marked class private and that makes this uglieness a burden.
Jun 22 2022
next sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 05:41:19 UTC, Ola Fosheim Grøstad 
wrote:
 Stronger typing is desirable in complex performance oriented 
 system level programming. This is the biggest weakness of C. 
 Modules are clearly weaker than class/struct level protection. 
 Weaker typing is not better in this context.

 But «private(this)» is inconsistent and ugly. Other languages 
 being ugly is not a good excuse. Most fields should be marked 
 class private and that makes this uglieness a burden.
Well, strong typing is the foundation of structured programming. And structred programming is the foundation of scalable programming. So I'd argue is more that 'desirable'. It's actually necessary. Even Javascript has realised this recently. It's more powerful than D now, as far as strong typing goes! I never thought I'd say that...yeepers! But really, the burden of typing this, just once in your class: private(this): seems pretty trivial to the burden of putting every class in its own module, just to simulate a strong type.
Jun 22 2022
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 23 June 2022 at 05:51:47 UTC, forkit wrote:
 Even Javascript has realised this recently. It's more powerful 
 than D now, as far as strong typing goes! I never thought I'd 
 say that...yeepers!
Yes, I think TypeScript paved the way. TypeScript actually gets many things right, except the stuff it gets from JavaScript... 😁
 But really, the burden of typing this, just once in your class:

 private(this):
My experience from C++ is that I end up with multiple «private:» to get the best structure. D needs to stop thinking that it can take just one more ugly. Syntax matters.
Jun 22 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 06:09:41 UTC, Ola Fosheim Grøstad 
wrote:
 My experience from C++ is that I end up with multiple 
 «private:» to get the best structure.

 D needs to stop thinking that it can take just one more  ugly. 
 Syntax matters.
well whatever the syntax.... it's a little irrelevant at such an early stage. I'm using dkorpel's 'private-this' branch of dmd, and it's doing just what I want. The world has not collapsed ;-) https://github.com/dkorpel/dmd
Jun 22 2022
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 23 June 2022 at 06:33:37 UTC, forkit wrote:
 I'm using dkorpel's 'private-this' branch of dmd, and it's 
 doing just what I want.
Good for you! :)
Jun 23 2022
prev sibling parent deadalnix <deadalnix gmail.com> writes:
On Thursday, 23 June 2022 at 05:51:47 UTC, forkit wrote:
 Even Javascript has realised this recently. It's more powerful 
 than D now, as far as strong typing goes! I never thought I'd 
 say that...yeepers!
Have you considered that this move is 1/ not that recent (it 10+ years old now) and 2/ some of the people you are arguing against have worked on building these systems?
Jun 23 2022
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Thursday, 23 June 2022 at 05:41:19 UTC, Ola Fosheim Grøstad 
wrote:
 Stronger typing is desirable in complex performance oriented 
 system level programming. This is the biggest weakness of C. 
 Modules are clearly weaker than class/struct level protection. 
 Weaker typing is not better in this context.
It is exceedingly uncommon for a property to be all good or all bad. If it was unambiguously true that tighter control is always better, all languages would just do very tight control. But in practice, they don't. Usually, while you increase things on one axis, you also diminish them on another.
Jun 23 2022
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 23 June 2022 at 09:30:49 UTC, deadalnix wrote:
 Usually, while you increase things on one axis, you also 
 diminish them on another.
I don't see how providing more expressive constraints diminish anything on a semantic level if sound. There is an implementation/design/educational cost, but history suggests that languages over time add more expressive constraints: C++ concepts/consteval, Python typing module, TypeScript, JavaScript classes/private.
Jun 23 2022
next sibling parent reply Dom Disc <dominikus scherkl.de> writes:
On Thursday, 23 June 2022 at 09:42:59 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 23 June 2022 at 09:30:49 UTC, deadalnix wrote:
 Usually, while you increase things on one axis, you also 
 diminish them on another.
I don't see how providing more expressive constraints diminish anything on a semantic level if sound.
No, but this whole discussion is only about coding style (putting each class in its own module or not). And from style guide perspective having more options is always bad. It reduces the readability.
Jun 23 2022
next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 23 June 2022 at 09:49:25 UTC, Dom Disc wrote:
 No, but this whole discussion is only about coding style 
 (putting each class in its own module or not). And from style 
 guide perspective having more options is always bad. It reduces 
 the readability.
From a readability perspective and an educational cost perspective having «private» mean anything but the conventional class-private is a mistake. So that has clearly not been the main consideration when landing on the current setup. It is by and large a personal opinion design. Much of the D design is personal/opinionated. Anyway, if you look at Phobos then you'll realize that the language does not affect module structure to a significant degree. Having more constraints, will not make people make create more disorganized code. If anything you get more structure, better documentation using language means and more opportunities to clearly organize your code. (But as noted before, this is not D's biggest issue…)
Jun 23 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 09:49:25 UTC, Dom Disc wrote:
 ...
 No, but this whole discussion is only about coding style 
 (putting each class in its own module or not). And from style 
 guide perspective having more options is always bad. It reduces 
 the readability.
Coding style? Ummm .. no. Why is it, that some people ***still*** don't get it. It's about being able to declare, as strongly typed, abstract data object, that is responsible for declaring and maintaining its own invariants, and where the compiler can enforce those invariants. It is perhaps, the single most important concept for good, scalable, software engineering. Sure, D has a 'workaround' where you can 'simulate' this. But it's deficient. As soon as you add any code whatsover to the module, the simulation dissolves. The only solution to not having a strongly typed abstract data object, is to have one. It makes software engineering better, not worse. But more importantly, you get to decide whether to use it or not. Like it's completely up to you. You don't like it? Don't use it. Simple. If it's the thing you've waiting for, for years, then woohoo! At least someone had the balls (or otherwise), to take this to the next level and actually try putting it in as a preview, so people can try it. Again, totally up to you to try it or not. want to try it: '-preview=privateThis' don't want to try it: '' It's up to **you** C has it's million dollar mistake. I think missing this important feature was D's million 'user' mistake (a million missing users because of it).
Jun 23 2022
next sibling parent reply Dom Disc <dominikus scherkl.de> writes:
On Thursday, 23 June 2022 at 10:16:42 UTC, forkit wrote:

 strongly typed, abstract data object is perhaps, the single most
 important concept for good, scalable, software engineering.

 Sure, D has a 'workaround' where you can 'simulate' this.
This is no workaround. It's one of Ds basic design choices, and done so for reasons (the friend-problem), not accidentally.
 it's deficient. As soon as you add any code whatsover to the 
 module, the simulation dissolves.
You can prevent that from happening (supported by the OS!). Much better as you can prevent someone who has access to a module from changing one of the classes within it (there you have no chance at all). I call that strong typed. Much, much stronger than with multiple classes within one file!
 I think missing this important feature was D's million 'user' 
 mistake (a million missing users because of it).
There is no feature missing. And I still find the way D realizes the same as other languages do with class private much better. Far from a mistake.
Jun 23 2022
parent Dom Disc <dominikus scherkl.de> writes:
The longer I think about it (and that's really long, because of 
this thread), the more I dislike class private.
It's a bogus concept.
It make you think you have a strong type, but you can't prevent 
others from messing it up.

Maybe in very small projects (where it makes at least a little 
bit of sense to put everything in few files) it helps you to 
avoid making stupid mistakes (like using some private field in a 
function that shouldn't use it), but if the project grows the 
code must be re-organized anyway.
So it is much better to learn to do this from the start. And 
having one class in one file provides the same "protection" from 
stupid mistakes.
Jun 23 2022
prev sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Thursday, 23 June 2022 at 10:16:42 UTC, forkit wrote:
 Coding style?

 Ummm .. no.

 Why is it, that some people ***still*** don't get it.
I think that all people here get it. They don't agree on making an elephant out of mosquito.
Jun 23 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 10:34:50 UTC, Alexandru Ermicioi 
wrote:
 On Thursday, 23 June 2022 at 10:16:42 UTC, forkit wrote:
 Coding style?

 Ummm .. no.

 Why is it, that some people ***still*** don't get it.
I think that all people here get it. They don't agree on making an elephant out of mosquito.
But it is an elehpant, not a mosquito. That's the point I've been trying to make - which it seems, is still not getting across to some.
Jun 23 2022
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 23 June 2022 at 10:36:02 UTC, forkit wrote:
 On Thursday, 23 June 2022 at 10:34:50 UTC, Alexandru Ermicioi 
 wrote:
 On Thursday, 23 June 2022 at 10:16:42 UTC, forkit wrote:
 Coding style?

 Ummm .. no.

 Why is it, that some people ***still*** don't get it.
I think that all people here get it. They don't agree on making an elephant out of mosquito.
But it is an elehpant, not a mosquito. That's the point I've been trying to make - which it seems, is still not getting across to some.
Seriously, everyone here gets it. If they didn't before, they surely do by now. It's just that we disagree with you. That's it. And so far, you still haven't shown any real problem that `private(this)` solves. Violation of encapsulation at the class boundary within the module *in D* is a conceptual problem. That's not true in other languages, but it's true here. That's because for the public API, where encapsulation actually matters in D, it happens at the module level. I could go all "I can't understand why you don't get it", but I haven't gone there and I'm not going to. Fundamentally, you're refusing to accept that it isn't an elephant after all. And that's fine. That's your prerogative. But please, just accept that we do understand you points and simply disagree with you. Repeating them endlessly isn't convincing anyone. If you want to convince someone, show us a real problem that `private(this)` solves *in D*. And good luck! I'll keep an eye out for the post that gets there.
Jun 23 2022
prev sibling next sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Thursday, 23 June 2022 at 10:36:02 UTC, forkit wrote:
 But it is an elehpant, not a mosquito.
 That's the point I've been trying to make - which it seems, is 
 still not getting across to some.
Well then you failed in your task. Perhaps changing the approach would help here. I'd recommend to try and tone down a bit the emotions (aggressiveness mostly) in your posts, and provide enough evidence that it is indeed a problem, for people asking for proof (mostly bugs caused by having no private to class modifier). Overall you did have some effect (this topic with restricted).
Jun 23 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 10:50:26 UTC, Alexandru Ermicioi 
wrote:
 On Thursday, 23 June 2022 at 10:36:02 UTC, forkit wrote:
 But it is an elehpant, not a mosquito.
 That's the point I've been trying to make - which it seems, is 
 still not getting across to some.
Well then you failed in your task. Perhaps changing the approach would help here.
Well, my task, was to highlight this issue in D, and stop it from always being stuffed under the rug by the 'opposers'. Thanks to dkorpel, for 'volunteering' his time and effort, to really move this forward (not as a new language feature, but as something you can try out, if you want). So I'd say, the straedgy worked, just fine ;-) Making 'noise' was, sadly, the only way to get any movement on this. A DIP, at this point, would have resulted in absolutely nothing occuring. (probably why so many were encouraging me to take that path instead). If anyone needs me, I'll be playing with 'private(this)' in dkorpel's branch of dmd.
Jun 23 2022
next sibling parent reply The Zealot <zod zod.zod> writes:
On Thursday, 23 June 2022 at 11:04:40 UTC, forkit wrote:
 On Thursday, 23 June 2022 at 10:50:26 UTC, Alexandru Ermicioi 
 wrote:
 On Thursday, 23 June 2022 at 10:36:02 UTC, forkit wrote:
 But it is an elehpant, not a mosquito.
 That's the point I've been trying to make - which it seems, 
 is still not getting across to some.
Well then you failed in your task. Perhaps changing the approach would help here.
Well, my task, was to highlight this issue in D, and stop it from always being stuffed under the rug by the 'opposers'. Thanks to dkorpel, for 'volunteering' his time and effort, to really move this forward (not as a new language feature, but as something you can try out, if you want). So I'd say, the straedgy worked, just fine ;-) Making 'noise' was, sadly, the only way to get any movement on this. A DIP, at this point, would have resulted in absolutely nothing occuring. (probably why so many were encouraging me to take that path instead). If anyone needs me, I'll be playing with 'private(this)' in dkorpel's branch of dmd.
So instead of just implementing it yourself, you had others do your work, and now you won't even go and write the DIP you were gathering opinions for. Good job....
Jun 23 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 11:10:58 UTC, The Zealot wrote:
 So instead of just implementing it yourself, you had others do 
 your work, and now you won't even go and write the DIP you were 
 gathering opinions for. Good job....
At no point did I agree to write a DIP. In fact, I'm pretty sure I said the opposite, many times. Also, I do not even the slightest technical skills or knowledge to even begin to think about how this would be implemented. I certainly never expected anyone to actually have the balls (or otherwise) to just go do it .. that was an unexpected bonus ;-)
Jun 23 2022
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 23 June 2022 at 11:16:39 UTC, forkit wrote:
 I certainly never expected anyone to actually have the balls 
 (or otherwise) to just go do it .. that was an unexpected bonus 
 ;-)
But you got what you wanted then, so now we can put this issue on the back-burner ;)
Jun 23 2022
parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 11:21:41 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 23 June 2022 at 11:16:39 UTC, forkit wrote:
 I certainly never expected anyone to actually have the balls 
 (or otherwise) to just go do it .. that was an unexpected 
 bonus ;-)
But you got what you wanted then, so now we can put this issue on the back-burner ;)
yes. I'm done ;-)
Jun 23 2022
prev sibling parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 11:16:39 UTC, forkit wrote:

look ma...

// ----
module test;
 safe:

import std;

class Base
{
     private(this) int x = 100;
     private int y = 200;
}

class Derived : Base
{
     //public int x = 200;
}

void main()
{
     Derived d = new Derived();
     writeln(d.x);
     writeln(d.y);
}
// ------


 dmdnew -preview=privateThis privatethis.d privatethis.d(21): 
 Error: no property `x` for type `test.Derived`
woohoo! 6 years in the making!!! (just to do what I've able to do for 20+ years in other languages).
Jun 23 2022
prev sibling next sibling parent reply Dom Disc <dominikus scherkl.de> writes:
On Thursday, 23 June 2022 at 11:04:40 UTC, forkit wrote:

 Well, my task, was to highlight this issue in D, and stop it 
 from always being stuffed under the rug by the 'opposers'.
It was never "under the rug", as it popped up now and then by newbies. If anything, you managed to change my opinion from "I don't need it, but who cares" to "It would be a failure to add it". I would oppose any such DIP and hope Daniels branch won't make it in the mainstream. "restricted" (or hidden/sees which I still think would be better names) would be a different thing, as this provides something new (preventing member functions from accessing specific fields). And fixes to the invariant handling are of course a good thing.
Jun 23 2022
parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 11:24:36 UTC, Dom Disc wrote:
 It was never "under the rug", as it popped up now and then by 
 newbies.

 If anything, you managed to change my opinion from "I don't 
 need it, but who cares" to "It would be a failure to add it".
 I would oppose any such DIP and hope Daniels branch won't make 
 it in the mainstream.

 "restricted" (or hidden/sees which I still think would be 
 better names) would be a different thing, as this provides 
 something new (preventing member functions from accessing 
 specific fields). And fixes to the invariant handling are of 
 course a good thing.
Just when I thought I was out, they pull me back in!
Jun 23 2022
prev sibling parent reply Dennis <dkorpel gmail.com> writes:
On Thursday, 23 June 2022 at 11:04:40 UTC, forkit wrote:
 Thanks to dkorpel, for 'volunteering' his time and effort, to 
 really move this forward (not as a new language feature, but as 
 something you can try out, if you want).

 So I'd say, the straedgy worked, just fine ;-)

 Making 'noise' was, sadly, the only way to get any movement on 
 this.
Note that I don't actually want the feature myself, but I was curious how complex it would actually be to implement, and wanted to show that the discussion does not have to be a harsh conflict between two self-interested camps. Maybe when there's something concrete on the table we can all stop bickering over principles, definitions, quotes from authority figures etc. and get some real world experience. And when it gets rejected, at least you can still forkit ;) I did NOT want to show that making noise on the forum is the way to get your feature in. Please don't keep bringing up the same points over and over, especially in other threads like [this one](https://forum.dlang.org/post/jjxxvzaehgzzwucapmap forum.dlang.org).
Jun 23 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 11:54:26 UTC, Dennis wrote:
 Note that I don't actually want the feature myself, but I was 
 curious how complex it would actually be to implement, and 
 wanted to show that the discussion does not have to be a harsh 
 conflict between two self-interested camps. Maybe when there's 
 something concrete on the table we can all stop bickering over 
 principles, definitions, quotes from authority figures etc. and 
 get some real world experience. And when it gets rejected, at 
 least you can still forkit ;)
They keep pulling me back in!! But yes. So it seems we both wanted **exactly** the same thing. Not some drawn out process where everyone will complain about this and that... but something one can start writing code with, and see what happens from there. Thanks for you reffort, whether you like the idea or not ;-)
 I did NOT want to show that making noise on the forum is the 
 way to get your feature in. Please don't keep bringing up the 
 same points over and over, especially in other threads like 
 [this 
 one](https://forum.dlang.org/post/jjxxvzaehgzzwucapmap forum.dlang.org).
This actually was never about making noise to 'get the feature in', but making noise to discover what people think about the idea, which is very interesting in itself. The feature, even if it got into D, would not change my perspective on D, just based on that one feature. I still think other languages much better understand the concept of a user-defined type, than D, whose user-defined type outsources its own destiny, to the module! That is a complete joke to me. And always will be. Mmm...I'm not sure why you're picking on my post there, since it was clearly in response to another idea.. but hey... In any case, I reserve the right to bring up the point, or any point, whenever, and whereever I think it is appropriate.
Jun 23 2022
parent reply Jordan Wilson <wilsonjord gmail.com> writes:
On Thursday, 23 June 2022 at 21:32:14 UTC, forkit wrote:
 In any case, I reserve the right to bring up the point, or any 
 point, whenever, and whereever I think it is appropriate.
All power to you. I reserve the right to bring up any issues with the manner in which points are being made. You may retort.. I know you will ;-)
Jun 23 2022
parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 21:55:40 UTC, Jordan Wilson wrote:
 On Thursday, 23 June 2022 at 21:32:14 UTC, forkit wrote:
 In any case, I reserve the right to bring up the point, or any 
 point, whenever, and whereever I think it is appropriate.
All power to you. I reserve the right to bring up any issues with the manner in which points are being made. You may retort.. I know you will ;-)
Yes. that is your right. I'm a firm believer, that people have rights, and they need to be upheld. If only that were true for my user-defined-type 'person', in D. It's rights have been taken away in D :-(
Jun 23 2022
next sibling parent Dom Disc <dominikus scherkl.de> writes:
On Thursday, 23 June 2022 at 21:59:22 UTC, forkit wrote:
 If only that were true for my user-defined-type 'person', in D.

 It's rights have been taken away in D :-(
Yeah, you should not have given write access to other people. Oh, I forgot. You have conflated everything in one file which everybody can edit... too bad.
Jun 23 2022
prev sibling parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 21:59:22 UTC, forkit wrote:

btw.

does private(this) address (in any way) the problem outlined in 
the 'original' subject of this thread?
Jun 23 2022
prev sibling parent deadalnix <deadalnix gmail.com> writes:
On Thursday, 23 June 2022 at 10:36:02 UTC, forkit wrote:
 But it is an elehpant, not a mosquito.

 That's the point I've been trying to make - which it seems, is 
 still not getting across to some.
If it was an elephant, you'd have an abundant number of concrete exemple of problems caused by this. You don't. So it's not an elephant.
Jun 23 2022
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Thursday, 23 June 2022 at 09:42:59 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 23 June 2022 at 09:30:49 UTC, deadalnix wrote:
 Usually, while you increase things on one axis, you also 
 diminish them on another.
I don't see how providing more expressive constraints diminish anything on a semantic level if sound. There is an implementation/design/educational cost, but history suggests that languages over time add more expressive constraints: C++ concepts/consteval, Python typing module, TypeScript, JavaScript classes/private.
Then you see how providing more has a cost, at least and `implementation/design/educational` one. So there is a point at wish adding that expressivness is counter productive, it is at the point when the value of the extra things that you can express is lower than the cost incurred by implementing the change required for that extra expressivness to be possible. There are other costs: - Tooling will not support that feature initially. D tends to be cavalier with that, and as a result, has worse tooling than pretty much any other language out there. - There are now many ways to express the same thing (put things in different module and use `private` or put thing in the same module and use `private(this)`). This has an adverse effect on readability by providing ways to subvert the expectations of the reader. I'm also convinced that there are costs I cannot really pinpoint, but that are real. The existing landscape clearly demonstrate this. For instance, while Java provides class level visibility, it is actually commonplace to have one Java class per file in numerous projects. Amongst the top languages, more than half have little to no visibility constraints, and these who do like Java tend to have idioms to map visibility with files. There is something there that remains under explored.
Jun 23 2022
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 23 June 2022 at 10:18:29 UTC, deadalnix wrote:
 So there is a point at wish adding that expressivness is 
 counter productive, it is at the point when the value of the 
 extra things that you can express is lower than the cost 
 incurred by implementing the change required for that extra 
 expressivness to be possible.
Yes, there is a cost if the syntax is messed up or if there is a breaking change. The cost for adding the feature is higher now than if one at a later stage choose to clean up the syntax (and thus get a breaking change anyway). So it probably should wait for a more general syntax cleanup.
Jun 23 2022
parent forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 10:29:46 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 23 June 2022 at 10:18:29 UTC, deadalnix wrote:
 So there is a point at wish adding that expressivness is 
 counter productive, it is at the point when the value of the 
 extra things that you can express is lower than the cost 
 incurred by implementing the change required for that extra 
 expressivness to be possible.
Yes, there is a cost if the syntax is messed up or if there is a breaking change. The cost for adding the feature is higher now than if one at a later stage choose to clean up the syntax (and thus get a breaking change anyway). So it probably should wait for a more general syntax cleanup.
D is already paying a big price, IMO. If I look at the languages available, and the features they have that would enable me to do better software engineering, D would not even be on the list! Swift would likely be no.1 - the 'choices' they offer to the programmer, are just superb! I still think C++ got it right. I just wish they had GC, cause i got better things to do than worry about that crap these days. I actually like the C++ friends feature (although it's subject to misuse, like any feature really). But D.. nowhere to be found, in that list. Maybe on someother list.
Jun 23 2022
prev sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 23 June 2022 at 10:18:29 UTC, deadalnix wrote:
 ..
 Then you see how providing more has a cost, at least and 
 `implementation/design/educational` one. So there is a point at 
 wish adding that expressivness is counter productive, it is at 
 the point when the value of the extra things that you can 
 express is lower than the cost incurred by implementing the 
 change required for that extra expressivness to be possible.

 There are other costs:
  - Tooling will not support that feature initially. D tends to 
 be cavalier with that, and as a result, has worse tooling than 
 pretty much any other language out there.
  - There are now many ways to express the same thing (put 
 things in different module and use `private` or put thing in 
 the same module and use `private(this)`). This has an adverse 
 effect on readability by providing ways to subvert the 
 expectations of the reader.

 I'm also convinced that there are costs I cannot really 
 pinpoint, but that are real. The existing landscape clearly 
 demonstrate this. For instance, while Java provides class level 
 visibility, it is actually commonplace to have one Java class 
 per file in numerous projects.  Amongst the top languages, more 
 than half have little to no visibility constraints, and these 
 who do like Java tend to have idioms to map visibility with 
 files.

 There is something there that remains under explored.
There's always a cost in giving people choice. is to use it, and my software engineering is better because i make that choice. If it was useless, i wouldn't use it. In D, I don't have that choice. I mean this is something you need to take seriously. This is not an argument over bracing preferences. This is an argument for, a programming language to provide proper support for strongly typed abstract objects. That's all there is to this. All the other nonsense in these threads, is just distracting noise to confuse people, and to ensure they never get to make that choice, in D.
Jun 23 2022
parent deadalnix <deadalnix gmail.com> writes:
On Thursday, 23 June 2022 at 10:34:53 UTC, forkit wrote:

 is to use it, and my software engineering is better because i 
 make that choice. If it was useless, i wouldn't use it.

 In D, I don't have that choice.
You have this choice: put things in a different module.
Jun 23 2022
prev sibling parent The Zealot <zod zod.zod> writes:
On Wednesday, 22 June 2022 at 23:31:28 UTC, user1234 wrote:
 On Wednesday, 22 June 2022 at 23:08:38 UTC, deadalnix wrote:
 On Wednesday, 22 June 2022 at 21:30:07 UTC, forkit wrote:
 I refer maxhaton back to the seminal paper on the benefits of 
 abstract data types:

 Programming with abstract data types - Liskov and Zilles 1974

 https://dl.acm.org/doi/pdf/10.1145/942572.807045
I wish you understood that every comment that you make where you fail to present any concrete instance of the problem caused weakens your case. Assuming the people you are talking to are not well versed in the concept of asbtract data types is somewhat amusing, but I'm afraid, also playing against your case.
to be fair, I think that, to any example presented here, the answer will be "put the aggregate declaration in its own module". But let's try something simple: ```d struct VLA { private: void* ptr; size_t length; public: void setLength(size_t value); } struct Other { VLA vla; void imBad() { length += 1; // now I may have faults or not when reading the vla } } ``` It's about being strict with yourself. What if I'm not really good, make stupid mistakes ? Now I have a security barrier, I can use `private(this)`, the compiler helps me with an error.
there's no practical difference to this: ``` struct VLA { private: void* ptr; size_t length; public: void setLength(size_t value); void imBad() { vla.length += 1; // now I may have faults or not when reading the vla } } struct Other { VLA vla; void breaktheworld() {vla.imBad();} } ``` in both cases your function breaks any invariants VLA might have. The real question is, why is VLA declared in the module scope in the first place? This is a prime example of why _class private_ encourages bad code design.
Jun 23 2022
prev sibling parent Max Samukha <maxsamukha gmail.com> writes:
On Tuesday, 21 June 2022 at 23:59:03 UTC, deadalnix wrote:

 Considering you failed to point at any concrete problem caused 
 by that design decision, I'll now have to increase my 
 confidence in the fact that there is none.
It's interesting how you are at the same time denying the problem exists and offering a kludge to solve it. )
 After, if there were, you'd have stated them.
Jun 21 2022
prev sibling parent Max Samukha <maxsamukha gmail.com> writes:
On Tuesday, 21 June 2022 at 08:37:55 UTC, Max Samukha wrote:

 However, this will only work because currently it is impossible 
 to access variables from the outside at all.
variables -> function-local variables
Jun 21 2022