Preparing for the New DIP Process

Jonathan M Davis newsgroup.d at jmdavisprog.com
Fri Jan 26 03:38:03 UTC 2024


On Thursday, January 25, 2024 8:03:41 AM MST Max Samukha via Digitalmars-d-
announce wrote:
> On Monday, 22 January 2024 at 23:28:40 UTC, Jonathan M Davis
>
> wrote:
> > Of course, ultimately, different programmers have different
> > preferences, and none of us are going to be happy about
> > everything in any language.
>
> It's not only about preferences. The feature is inconsistent with
> how 'invariant' and 'synchronized' are specified. They imply
> class-instance-level private, while the language dictates
> module-level. Consider:
>
> ```
> synchronized class C
> {
>      private int x;
>      private int y;
>
>      invariant () { assert (x == y); }
> }
>
> void foo(C c)
> {
>      // mutate c
> }
> ```
>
> With module-level private, 'foo' is part of C's public interface,
> but it neither locks on c, nor runs the invariant checks. I
> personally have no idea how to fix that sensibly except by
> ditching class invariant/synchronized entirely.

Well, sychronized is actually a function attribute, not a class attribute
(TDPL talks about synchronized classes, but they've never actually been a
thing; it was just a planned idea that was never implemented). You can stick
synchronized on the class itself, but it still only affects the member
functions. So, mutating the class object via non-member functions in the
module really isn't any different from mutating the object with member
functions which aren't marked with synchronized. So, if anything here, I
would argue that the confusion comes from being allowed to stick attributes
on a class and then have them affect the member functions. It does allow you
to stick the attribute in one place and then affect the entire class, but
I'm inclined to think that it probably shouldn't have been allowed in cases
where the attribute isn't actually for the class itself.

Of course, the change that I'd really like to see here is synchronized
removed from the language, since I think that it was definitely a misfeature
(along with having a monitor inside of every class instance to allow
synchronized to work, whether the type is shared or not or has an
synchronized methods or not).

Regardless, because synchronized is not at all a class attribute, I don't
agree that it implies anything related to class-level private, much as I can
see how being allowed to put it directly on a class could cause confusion.

As for invariants, all that the spec promises is that they're called when
public member functions are called. So, again, having a module-level
function directly mutate the members doesn't really violate anything.
However, the part there that I do agree is questionable is that because the
module-level function could be public, it makes it so that it's pretty easy
to end up in a situation where an invariant is skipped when the object is
mutated by calling public functions from the module. But there are also
likely to be cases where it's useful to be able to bypass the invariant like
that (though obviously, it then requires that the code maintain the
invariant, just like @trusted code needs to maintain the promises of @safe).
So, I don't think that it's necessarily a problem that the language works
this way, but it's certainly true that it's something to be mindful of. And
if you want to explictly run the invariant in such sitations, then you can
just assert the class reference. But as with anything related to private, if
you want to guarantee that something only accesses an object via its public
API, you can always just put it in another module.

- Jonathan M Davis





More information about the Digitalmars-d-announce mailing list