Jump to page: 1 217  
Page
Thread overview
`restricted` member variables
Jun 20, 2022
Mike Parker
Jun 20, 2022
deadalnix
Jun 20, 2022
user1234
Jun 20, 2022
Mike Parker
Jun 20, 2022
Mike Parker
Jun 20, 2022
David Gileadi
Jun 20, 2022
bauss
Jun 20, 2022
Salih Dincer
Jun 20, 2022
Kagamin
Jun 20, 2022
Mike Parker
Jun 20, 2022
Dom Disc
Jun 20, 2022
Paul Backus
Jun 20, 2022
deadalnix
Jun 21, 2022
Mike Parker
Jun 21, 2022
deadalnix
Jun 21, 2022
Mike Parker
Jun 21, 2022
Mike Parker
Jun 21, 2022
deadalnix
Jun 21, 2022
The Zealot
Jun 21, 2022
The Zealot
Jun 21, 2022
forkit
Jun 21, 2022
The Zealot
Jun 21, 2022
bauss
Jun 21, 2022
Max Samukha
Jun 21, 2022
Max Samukha
Jun 21, 2022
The Zealot
Jun 21, 2022
bauss
Jun 21, 2022
bauss
Jun 21, 2022
bauss
Jun 21, 2022
deadalnix
Jun 21, 2022
bauss
Jun 21, 2022
Max Samukha
Jun 21, 2022
deadalnix
Jun 21, 2022
12345swordy
Jun 21, 2022
Chris Katko
Jun 22, 2022
claptrap
Jun 22, 2022
forkit
Jun 22, 2022
Sergey
Jun 22, 2022
forkit
Jun 22, 2022
claptrap
Jun 22, 2022
forkit
Jun 22, 2022
claptrap
Jun 22, 2022
claptrap
Jun 22, 2022
claptrap
Jun 22, 2022
deadalnix
Jun 22, 2022
forkit
Jun 22, 2022
deadalnix
Jun 22, 2022
forkit
Jun 22, 2022
forkit
Jun 22, 2022
forkit
Jun 21, 2022
forkit
Jun 21, 2022
deadalnix
Jun 22, 2022
forkit
Jun 22, 2022
forkit
Jun 22, 2022
forkit
Jun 22, 2022
forkit
Jun 22, 2022
Dennis
Jun 22, 2022
jmh530
Jun 22, 2022
forkit
Jun 22, 2022
Dennis
Jun 22, 2022
forkit
Jun 22, 2022
forkit
Jun 22, 2022
max haughton
Jun 22, 2022
forkit
Jun 22, 2022
deadalnix
Jun 22, 2022
forkit
Jun 22, 2022
deadalnix
Jun 22, 2022
forkit
Jun 23, 2022
Paul Backus
Jun 23, 2022
forkit
Jun 23, 2022
Paul Backus
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
Mike Parker
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
Mike Parker
Jun 23, 2022
deadalnix
Jun 23, 2022
Paul Backus
Jun 23, 2022
Mike Parker
Jun 23, 2022
The Zealot
Jun 23, 2022
forkit
Jun 23, 2022
Mike Parker
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
Jordan Wilson
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
Jordan Wilson
Jun 23, 2022
Dom Disc
Jun 23, 2022
Max Samukha
Jun 23, 2022
Alexandru Ermicioi
Jun 23, 2022
Max Samukha
Jun 22, 2022
forkit
Jun 22, 2022
deadalnix
Jun 22, 2022
deadalnix
Jun 22, 2022
forkit
Jun 22, 2022
user1234
Jun 22, 2022
user1234
Jun 22, 2022
deadalnix
Jun 23, 2022
forkit
Jun 22, 2022
Paul Backus
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
deadalnix
Jun 23, 2022
deadalnix
Jun 23, 2022
Dom Disc
Jun 23, 2022
forkit
Jun 23, 2022
Dom Disc
Jun 23, 2022
Dom Disc
Jun 23, 2022
Alexandru Ermicioi
Jun 23, 2022
forkit
Jun 23, 2022
Mike Parker
Jun 23, 2022
Alexandru Ermicioi
Jun 23, 2022
forkit
Jun 23, 2022
The Zealot
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
Dom Disc
Jun 23, 2022
forkit
Jun 23, 2022
Dennis
Jun 23, 2022
forkit
Jun 23, 2022
Jordan Wilson
Jun 23, 2022
forkit
Jun 23, 2022
Dom Disc
Jun 23, 2022
forkit
Jun 23, 2022
deadalnix
Jun 23, 2022
deadalnix
Jun 23, 2022
forkit
Jun 23, 2022
forkit
Jun 23, 2022
deadalnix
Jun 23, 2022
The Zealot
Jun 22, 2022
Max Samukha
Jun 21, 2022
Max Samukha
June 20, 2022

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 goes below the surface:

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:

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:

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:

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

I imagine this would be useful:

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:

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

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!

June 20, 2022

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.

June 20, 2022

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.

June 20, 2022

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.

June 20, 2022

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.

June 20, 2022

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?

June 20, 2022

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.

June 20, 2022

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.

June 20, 2022

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.

June 20, 2022

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.

« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10 11