June 20, 2022

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

June 20, 2022

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:

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 :-(

June 20, 2022

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:

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:

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.

June 20, 2022

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.

June 20, 2022

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:

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:

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.

June 21, 2022

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:

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 forminvariant(_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.

June 21, 2022

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:

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.

June 21, 2022

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.

June 21, 2022
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.

June 21, 2022

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.