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.