January 25
On Wednesday, 24 January 2024 at 22:32:12 UTC, FairEnough wrote:
> On Monday, 22 January 2024 at 23:28:40 UTC, Jonathan M Davis wrote:
>
> But the argument that it cannot cause a problem, is already shown to be wrong.

So it is good, that unit tests helped you to find how language is designed!
Good feature
January 25

On Thursday, 25 January 2024 at 00:19:54 UTC, Jordan Wilson wrote:

>

I can only assume lack of string interpolation was causing pain to more users, than a lack of class private, therefore it got implemented first.

String mixins are one the D’s killer features but the lack of string interpolation make them look like a mess.

January 25

On Thursday, 25 January 2024 at 07:56:50 UTC, Ogi wrote:

>

String mixins are one the D’s killer features but the lack of string interpolation make them look like a mess.

You can use q{}

mixin(q{
    static foreach(p; __traits(parameters))
    {{
        enum pname = __traits(identifier, p);
        static if(__traits(hasMember, this, pname)) {
            __traits(getMember, this, pname) = p;
            pragma(msg, "found member: " ~ pname);
            pragma(msg, __traits(getAttributes, p));
            pragma(msg, __traits(getAttributes, typeof(pname)));
            //pragma(msg, p);
        }
    }}
});
January 25
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.
January 25

On Thursday, 25 January 2024 at 15:03:41 UTC, Max Samukha wrote:

>

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.

private to module , goes against consistency, completeness, and redundancy pursued by D, just to maintain the uniqueness between D and C++!

January 25

On Thursday, 25 January 2024 at 15:14:30 UTC, zjh wrote:

>

private to module , goes against consistency, completeness, and redundancy pursued by D, just to maintain the uniqueness between D and C++!

It is just very funny!

January 25

On Thursday, 25 January 2024 at 15:03:41 UTC, Max Samukha 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.

Is there issue with module-private, invariant, and synchronized solely the result of the interaction between all three? Or is there an issue with module-private and invariant by themselves (i.e. if C is not synchronized)?

January 25
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



January 26

On Thursday, 25 January 2024 at 08:58:29 UTC, Danilo wrote:

>

You can use q{}

string wrap(string f) {
    return "void wrap_"~f~"() { "~f~"(); }";
}
void fun() {}
mixin(wrap("fun"));

Not only q{} will make this even less readable—it won’t even work.

January 26
On Thursday, 25 January 2024 at 15:03:41 UTC, Max Samukha 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.

This is the only valid reason for introducing class-private that's ever been put forth in this forum. I saw someone else post a similar argument around class invariants awhile back as well and it completely changed my mind on the issue.