April 10, 2022
On 10.04.22 17:04, Alexandru Ermicioi wrote:
> On Friday, 8 April 2022 at 18:00:14 UTC, rikki cattermole wrote:
>> Here is my test code that I used to determine what I needed to do to make const RC types useless (and hopefully safe).
>> ...
> 
> Isn't better then to try and find design patterns or rules for use with mutable RC structures?
> 
> All the talk across the years was basically about trying to eat the pancake and also at same time trying to keep it for later, and neither is done after all deliberation across the years. Perhaps it would be best to just break the existing immutable system, and redefine it to allow rc features found in C++ or other languages, or just have a limited version of rcs in D (compared to C++ or other languages employing them), and workaround those restrictions through some well defined rules and design patterns.
> 
> And when mentioning breaking the immutable system, I really mean breaking it, by removing the transitiveness it has, or some other major change, like not being really immutable, and therefore safe to put in readonly memory.
> 
> 

I think the solution of this particular issue should come down to one of:

- accept that `immutable` means immutable, only use it where it actually makes sense to enforce that restriction, derive valid compiler optimizations from a specification based on UB. No immutable RC is allowed. `immutable` values can always be put in readonly memory, simple story for CTFE accessing immutable values.

- accept that there could potentially be mutable parts in `immutable` structures exclusively for low-level purposes, separate `immutable` and `shared immutable`, explicitly specify valid compiler optimizations based on nondeterministic semantics. Immutable RC is a thing. Whether or not `immutable` values can be put in readonly memory depends on the particular type, more complicated story for CTFE accessing immutable values.

Anyway, this is by far not the only issue with qualifiers applied to user-defined types. Built-in slices and pointer types have magical interactions with qualifiers that user-defined types cannot reproduce.
April 10, 2022

On Sunday, 10 April 2022 at 13:02:07 UTC, Zach Tollen wrote:

>

On Sunday, 10 April 2022 at 05:41:36 UTC, Bruce Carneal wrote:

>

I view 1035 as a mechanism to extend the reach of @safe, to reduce the load on conscientious code reviewers.

One aspect of DIP1035 I'm confused about in this regard is item (1) in the proposed changes: "An aggregate with at least one @system field is an unsafe type."

This concerns me because it seems like it would extend the reach of @system, rather than @safe. It seems like having one @system variable would contaminate the whole structure so that you always had to use @trusted just to do anything with it.

Maybe I'm thinking too much...

The point of this is to prevent things like void-initialization of types with @system fields in @safe code. You can still access non-@system fields of the structure without using @trusted.

"Unsafe type" does not mean you can't use it in @safe code. Pointer types are unsafe types, for example, and you can use pointers in @safe code without any issues. What "unsafe type" means is that, in @safe code, your usage of that type is restricted to operations that the compiler knows will not cause memory corruption.

April 11, 2022
On 11/04/2022 3:04 AM, Alexandru Ermicioi wrote:
> Isn't better then to try and find design patterns or rules for use with mutable RC structures?

Yes.

But if the compiler allows RC to become const and not allow RC to occur, that is a bad situation to be in...

That is what my test code above does, it prevents you from using it with const as much as possible.

It is a workaround to a much larger problem.
April 11, 2022
On Sunday, 10 April 2022 at 23:12:03 UTC, rikki cattermole wrote:
>
> On 11/04/2022 3:04 AM, Alexandru Ermicioi wrote:
>> Isn't better then to try and find design patterns or rules for use with mutable RC structures?
>
> Yes.
>
> But if the compiler allows RC to become const and not allow RC to occur, that is a bad situation to be in...

This seems like a couple of edge cases and bugs that need to be rectified, in order to have proper safe mutable only RC structs. You should be able to disallow implicit cast to const of struct if it is desired to do so.

>
> That is what my test code above does, it prevents you from using it with const as much as possible.
>
> It is a workaround to a much larger problem.

Regarding const rc use, I think there can be a limited access to the payload, if you somehow prohibit taking the address of the payload or it's sub-elements. Perhaps instead of returning payload itself from rc struct, maybe it can be wrapped into a wrapper, that prevents any take of address when a field is accessed from payload, or payload itself.
April 11, 2022
On Monday, 11 April 2022 at 11:46:42 UTC, Alexandru Ermicioi wrote:
> On Sunday, 10 April 2022 at 23:12:03 UTC, rikki cattermole wrote:
>>
>> On 11/04/2022 3:04 AM, Alexandru Ermicioi wrote:
>>> Isn't better then to try and find design patterns or rules for use with mutable RC structures?
>>
>> Yes.
>>
>> But if the compiler allows RC to become const and not allow RC to occur, that is a bad situation to be in...
>
> This seems like a couple of edge cases and bugs that need to be rectified, in order to have proper safe mutable only RC structs. You should be able to disallow implicit cast to const of struct if it is desired to do so.

There's no issue here. You just write the copy constructor of RC!T to require a mutable source and destination object, and the compiler will refuse to copy a const(RC!T). (You can still pass by `const ref`, of course.)

> Regarding const rc use, I think there can be a limited access to the payload, if you somehow prohibit taking the address of the payload or it's sub-elements. Perhaps instead of returning payload itself from rc struct, maybe it can be wrapped into a wrapper, that prevents any take of address when a field is accessed from payload, or payload itself.

You can limit access by passing a `scope` reference to the payload to a callback function, as described in this comment:

https://github.com/dlang/phobos/pull/8368#issuecomment-1024917439
April 11, 2022
On Monday, 11 April 2022 at 14:44:18 UTC, Paul Backus wrote:
> There's no issue here. You just write the copy constructor of RC!T to require a mutable source and destination object, and the compiler will refuse to copy a const(RC!T). (You can still pass by `const ref`, of course.)

Obviously there are:
```d
import std;

void main()
{
    int j = 2;
    int k = 3;
    const r3 = Counted!int(&j);
    const(Counted!int) r4 = Counted!int(&k);
}

@safe struct Counted(T)
{
    private T* subject;
    private size_t* counter;

    this(T* subject)
    {
        this.counter = new size_t;
        this.subject = subject;
        *this.counter = 1;
    }

    this(ref T subject) const @disable;
    this(T* subject) const @disable;

    this(ref Counted!T counted)
    {
        this.subject = counted.subject;
        this.counter = counted.counter;
        ++(*this.counter);
    }

    this(ref Counted!(const T) counted) const @disable;
    this(ref const Counted!T counted) const @disable;
    this(ref Counted!T counted) const @disable;

    this(this) @disable;

    ~this()
    {
        (*this.counter)--;

        if ((*this.counter) == 0)
        {
            writeln("Freeing the subject: ", *this.subject);

            this.counter = null;
        }
    }

    // ~this() const @disable; Obviously another bug or uncharted area.

    void opAssign(ref Counted!T counted)
    {
        --(*this.counter);
        this.subject = counted.subject;
        this.counter = counted.counter;
        ++(*this.counter);
    }

    void opAssign(Counted!T counted)
    {
        this = counted;
    }

    void opAssign(ref const(Counted!T) counted) const @disable;
    void opAssign(const(Counted!T) counted) const @disable;
    void opAssign(Counted!(const T) counted) const @disable;
    void opAssign(ref Counted!(const T) counted) const @disable;
    void opAssign(ref Counted!T counted) const @disable;
    void opAssign(Counted!T counted) const @disable;

    void opCast(T)() @disable;
}
```

Or I missed something that will prevent these two use cases.


April 11, 2022
On Monday, 11 April 2022 at 16:40:42 UTC, Alexandru Ermicioi wrote:
> On Monday, 11 April 2022 at 14:44:18 UTC, Paul Backus wrote:
>> There's no issue here. You just write the copy constructor of RC!T to require a mutable source and destination object, and the compiler will refuse to copy a const(RC!T). (You can still pass by `const ref`, of course.)
>
> Obviously there are:
>
> [...]

I don't see what the problem here is. Two instances of `Counted!int` are created, and both are destroyed. No references are leaked or left dangling. If you try to copy-construct an additional instance, like

    auto r5 = r4;

...then the compiler correctly rejects the code.

Granted, it only works because the compiler-inserted destructor call ignores `const`, which is a little questionable, but I think in this case it's basically harmless.
April 12, 2022

On Saturday, 9 April 2022 at 06:25:10 UTC, vit wrote:

>

Ref counted pointers in D have problem:

RAII in D is bad: move ctor are not implemented,

Move ctor is in the process of making.

>

overloading copy ctors sometimes crash dmd,

Overloading cpCtors with rvalue ctors sometimes crash the compiler because we don't have all the cases fleshed out. However, with https://github.com/dlang/dmd/pull/13976 if you do not template your rvalue constructors then you should be fine.

>

copy ctors are not called from GC slices

This is also being worked on. We are templating the druntime hooks so cpCtors should be called then. Anyway, some cases have been fixed by now because and more will come (I know that Teo Dutu is almost done with templating the hooks that deal with ~= and ~ so cp ctors will be called for those).

>

dtors have bad interaction with stack tuples/value sequences and opCast, emplace...

Yeah, that's a big one.

April 13, 2022

On Sunday, 10 April 2022 at 14:34:41 UTC, Timon Gehr wrote:

>

You seem to be contradicting yourself. It's either bad logic or bad communication.

I think it's the latter. I think the chief source of bad communication is actually a design flaw in DIP1035:

https://forum.dlang.org/post/tgbwhgxzkrupdotylkms@forum.dlang.org

@system variables are not a bad idea. DIP1035's mistake is in thinking that anyone would ever want a @system variable by accident.

Once you subtract all of the evidence against me which relied on the design flaw in DIP1035, what part of your case still stands?

All of the actual use cases for @system variables — I mean real @system variables, not just unsafely initialized ones — that I have seen (some are illustrated in the DIP, but also in Steven Schveighoffer's really excellent presentation on tagged unions) involve preserving the invariant of a data structure by making sure the @system variable is only modified simultaneously with some other piece of data.

Which means, generally, they are modified along with a normal variable. If the @system variable had __mutable characteristics implicitly, the @system function in which it was modified would also be modifying a non-__mutable value. Such a function would error anyway.

Maybe there is some other natural use for @system variables. But none of the use cases I have seen seem particularly incompatible with the additional __mutable functionality.

>

You are basically stating that you will not move away from your position, no matter what.

All I'm doing is trying to make my position clear.

You have to consider everything I've been saying in the context of how @system variables should have been defined from the beginning — as always explicitly @system. (I didn't realize just how devastating DIP1035's alternative, "infer @system everywhere" design really was until I was forced to examine it more closely. I've now made my case about that in the other post.)

This goes for everything I've been saying. Apply the new filter of: "A variable is a @system variable iff it is explicitly marked @system."

Me:

> >

Again, the only question is whether having __metadata functionality will cause intractable pain to the use cases of @system which don't require it.

The solution to our debate — insofar as my claims deserve any merit at all — is to implement both DIP1035 and the __metadata DIP, with the additional requirement that all uses of __metadata be marked @system as well.

I stand by this statement, assuming modified DIP1035.

>

In other words, you will just move the goalposts until you can claim you were right.

I honestly don't think that's what I'm doing. My mistake was actually having too strong a sense of the right way to implement @system variables. I only realized too late that DIP1035 wasn't quite there.

--

I'm sorry for a lot of the stress I've caused. I'm pretty sure that everything I've been saying makes at least a little bit of sense, given what I have always meant (to myself at least ^_^) by "@system variable".

Zach

April 13, 2022

On Wednesday, 13 April 2022 at 12:31:44 UTC, Zach Tollen wrote:

>

Maybe there is some other natural use for @system variables. But none of the use cases I have seen seem particularly incompatible with the additional __mutable functionality.

Without conflating @system and __mutable:

struct Boolean
{
    @system ubyte payload; // must be 0 or 1 or buffer overflows could happen
}

immutable Boolean b; // can be placed in read-only data segment

When conflating @system and __mutable, b suddenly must be placed in mutable memory.