June 28, 2023
On Wednesday, 28 June 2023 at 17:40:25 UTC, bachmeier wrote:
> On Wednesday, 28 June 2023 at 08:00:23 UTC, FeepingCreature wrote:
>
>> I like this approach:
>>
>> ```
>> class C {
>>     private int i;
>> }
>> ...
>> void main() @system {
>>     auto c = new C;
>>     c.private.i = 5;
>> }
>> ```
>
> This would be a good change to the language.

I’m not sure, but I’m thinking ‘yes’.
June 28, 2023
On Wednesday, 28 June 2023 at 17:06:43 UTC, Richard (Rikki) Andrew Cattermole wrote:
> Oh how you dare me.


just do

__traits(getMember, foo, "i") = 2;


reflection bypasses private

June 28, 2023
On 6/28/23 10:38, bachmeier wrote:

> [Rich
> Hickey](https://harfangk.github.io/2017/12/08/rich-hickey-interview-from-codequarterly.html):

Amen! I've just finished reading most of it (skipped some Clojure specific parts).

The following part is worth quoting as well:

  "When we drop down to the algorithm level, I think OO can
   seriously thwart reuse. In particular, the use of objects
   to represent simple informational data is almost criminal
   in its generation of per-piece-of-information
   micro-languages, i.e. the class methods, versus far more
   powerful, declarative, and generic methods like
   relational algebra. Inventing a class with its own
   interface to hold a piece of information is like
   inventing a new language to write every short story. This
   is anti-reuse, and, I think, results in an explosion of
   code in typical OO applications."

One more quote both to stay unkind to my ex-favorite language and to relate to our ever-present discussions on the GC's appropriateness in libraries:

  "The complexity [of C++] is stunning. It failed as the
   library language it purported to be, due to lack of GC,
   in my opinion, and static typing failed to keep large OO
   systems from becoming wretched balls of mud. Large
   mutable object graphs are the sore point, and const is
   inadequate to address it. Once C++’s performance
   advantage eroded or became less important, you had to
   wonder—why bother? I can’t imagine working in a language
   without GC today, except in very special circumstances."

Ali

June 29, 2023
On Tuesday, 27 June 2023 at 21:53:59 UTC, Ali Çehreli wrote:
> My mind is not fully clear on this topic yet but some related things have been brewing in me for years.
>
> [...]

I have lost count of how many times my life has been made difficult by the lack of `private`.

I have also lost count of how many times my life has been made easier by the fact that I ruthlessly declare everything `private` unless it has good reason not to be.

Ease of refactoring = good, ergo `private` = good and should be the default.
June 29, 2023
On Thursday, June 29, 2023 8:44:05 AM MDT Atila Neves via Digitalmars-d wrote:
> On Tuesday, 27 June 2023 at 21:53:59 UTC, Ali Çehreli wrote:
> > My mind is not fully clear on this topic yet but some related things have been brewing in me for years.
> >
> > [...]
>
> I have lost count of how many times my life has been made difficult by the lack of `private`.
>
> I have also lost count of how many times my life has been made easier by the fact that I ruthlessly declare everything `private` unless it has good reason not to be.
>
> Ease of refactoring = good, ergo `private` = good and should be the default.

Yeah. As with many things, I think that it primarily comes down to good API design (which can be hard). private prevents implementation details from being mucked with, which can be a lifesaver when refactoring and can be a big help with testing and ensuring that things work as expected when other folks use your code. On the other hand, if you fail to make it so that the API provides what your users need, then it could easily be the case that some stuff that should have been available is locked behind private, making their lives harder (or even impossible, depending on what they're trying to do).

Similarly, if you actually plan your API around generic types, then it's much easier for folks to make it work with their own types, but it's not always obvious when you should be doing that vs designing an API around more specific types - and it's often the case that code goes from using more specific types to being more flexible as it matures (though that's harder to do in cases where you can't reasonably make sure that all user code gets updated when you make changes, which can make fixing such issues in open source code harder than in company code).

So, I'm very much in favor of private being the default, but programmers need to be aware of API issues that can come from being too specific with APIs and locking away stuff that users may actually need. Experience can help a lot with that, though it isn't always easy, and there are plenty of folks out there who just put something together that "works" and leave folks to deal with the mess when something better thought out would have been far more useful. Actively trying to come up with good APIs instead of something that just works can go a long way.

- Jonathan M Davis




June 29, 2023

On 6/29/23 10:44 AM, Atila Neves wrote:

>

On Tuesday, 27 June 2023 at 21:53:59 UTC, Ali Çehreli wrote:

>

My mind is not fully clear on this topic yet but some related things have been brewing in me for years.

[...]

I have lost count of how many times my life has been made difficult by the lack of private.

I have also lost count of how many times my life has been made easier by the fact that I ruthlessly declare everything private unless it has good reason not to be.

Ease of refactoring = good, ergo private = good and should be the default.

private is good for the library writer.

arbitrary access to private is good for the user/hacker.

Honestly though, since private data is accessible through an escape hatch hack (i.e. __traits(getMember)), and the library writer can just say "whatevs, you broke it, you bought it", I think we are in a reasonable space.

-Steve

June 29, 2023
On 6/28/23 4:00 AM, FeepingCreature wrote:

> I like this approach:
> 
> ```
> class C {
>      private int i;
> }
> ...
> void main() @system {
>      auto c = new C;
>      c.private.i = 5;
> }
> ```
> 

```d
auto usePrivate(T)(ref T thing) @system
{
   static struct GetMeThePrivateStuff
   {
     @disable this(this); // shouldn't be copied about, meant to be a temporary access
     private T* _thing; // "private" lol
     auto ref opDispatch(string s, Args...)(Args args)
     {
        static if(Args.length == 0)
           return __traits(getMember, *_thing, s);
        else
           return __traits(getMember, *_thing, s)(args);
     }
   }

   return GetMeThePrivateStuff(&thing);
}
```

Yeah, yeah, it needs work. But you get the idea. D is all-powerful.

-Steve
June 29, 2023
On Thu, Jun 29, 2023 at 05:54:28PM -0600, Jonathan M Davis via Digitalmars-d wrote:
> On Thursday, June 29, 2023 8:44:05 AM MDT Atila Neves via Digitalmars-d wrote:
[...]
> > I have lost count of how many times my life has been made difficult by the lack of `private`.
> >
> > I have also lost count of how many times my life has been made easier by the fact that I ruthlessly declare everything `private` unless it has good reason not to be.
> >
> > Ease of refactoring = good, ergo `private` = good and should be the default.
> 
> Yeah. As with many things, I think that it primarily comes down to good API design (which can be hard).
[...]

True.  It comes down to good API design. Which, as you say, is very hard, probably harder than most people realize.  It's easy to slap an ad hoc API onto your library functions, but over time it will prove inadequate for user needs and they will feel frustrated over why certain things are locked behind private.

IME, it takes several iterations of actually using a particular API before it becomes clear where the friction points are and what are possible alternative designs that may work better for user code. (And also, which parts of the API are perhaps needlessly complex and could probably be simplified.) The problem is that if you have actual users during this period of time, they will start writing code that depends on the current API, which obligates you to support an inferior API even after a better design emerges.


> Similarly, if you actually plan your API around generic types, then it's much easier for folks to make it work with their own types, but it's not always obvious when you should be doing that vs designing an API around more specific types
[...]

Yeah, there's definitely a danger of premature generalization. Before you have experience designing a certain library, it's hard to predict what's worth generalizing and what isn't.  But it's hard to gain experience without people actually using your library, which then binds you to the non-optimal initial API.  So it's a catch-22.

API design is hard.


T

-- 
What do you mean the Internet isn't filled with subliminal messages? What about all those buttons marked "submit"??
June 29, 2023

On 6/29/23 10:15 PM, Steven Schveighoffer wrote:

>
auto usePrivate(T)(ref T thing) @system
{
    static struct GetMeThePrivateStuff
    {
      @disable this(this); // shouldn't be copied about, meant to be a temporary access
      private T* _thing; // "private" lol
      auto ref opDispatch(string s, Args...)(Args args)
      {
         static if(Args.length == 0)
            return __traits(getMember, *_thing, s);
         else
            return __traits(getMember, *_thing, s)(args);
      }
    }

    return GetMeThePrivateStuff(&thing);
}

Oh wait, the __traits(getMember) trick doesn't work on member functions, interesting...

So maybe half-powerful ;)

-Steve

June 30, 2023
On Friday, 30 June 2023 at 02:21:42 UTC, H. S. Teoh wrote:
> On Thu, Jun 29, 2023 at 05:54:28PM -0600, Jonathan M Davis via Digitalmars-d wrote:
>> [...]
> [...]
>> [...]
> [...]
>
> True.  It comes down to good API design. Which, as you say, is very hard, probably harder than most people realize.  It's easy to slap an ad hoc API onto your library functions, but over time it will prove inadequate for user needs and they will feel frustrated over why certain things are locked behind private.
>
> IME, it takes several iterations of actually using a particular API before it becomes clear where the friction points are and what are possible alternative designs that may work better for user code. (And also, which parts of the API are perhaps needlessly complex and could probably be simplified.) The problem is that if you have actual users during this period of time, they will start writing code that depends on the current API, which obligates you to support an inferior API even after a better design emerges.
>
>
>> [...]
> [...]
>
> Yeah, there's definitely a danger of premature generalization. Before you have experience designing a certain library, it's hard to predict what's worth generalizing and what isn't.  But it's hard to gain experience without people actually using your library, which then binds you to the non-optimal initial API.  So it's a catch-22.
>
> API design is hard.
>
>
> T

API design is indeed hard. Which makes it all the more imperative to not accidentally design one with implementation details that users downstream start depending on. That is: API design needs to be a conscious opt-in decision and not "I guess I didn't think about the consequences of leaving the door to my flat open all the time and now there are people camping in my living room".