July 19, 2019
On Friday, 19 July 2019 at 01:24:24 UTC, Walter Bright wrote:
> On 7/18/2019 4:31 AM, Olivier FAURE wrote:
>> Rust as it exists today is a vast language designed almost from the ground up to accommodate the borrowing model. It relies on several features that do not (and may never) exist in D, so saying "we're going to use a memory model like the one Rust has" is extremely vague,
>
> The only one mutable pointer XOR one or more const pointers is not a difficult concept. A sufficient description of it is included in the DIP, and a link provided for those who want to learn more.

Also, please don't be condescending to me.

Yes, "one mutable pointer XOR one or more const pointers" is simple. It's not what this DIP is proposing.
July 19, 2019
On Friday, 19 July 2019 at 08:32:13 UTC, Mike Franklin wrote:
> void main() @safe
> {
>     doSomething(foo(), bar());
> }
>
> How can the compiler statically determine whether `foo` and `bar` will return a reference to the same data?
>
> It seems the language or type system must provide this guarantee, which would require a full-fledged ownership/borrowing system to accurately enforce what this DIP is proposing.

From what I understand it won't with this dip. foo and bar do not refer to the same "memory object"
July 19, 2019
On Friday, 19 July 2019 at 07:59:14 UTC, Walter Bright wrote:
> Write a function that passes both the OutBuffer reference, and the result of peekSlice(). In that function, call writeByte(). Boom.
>
> The example in the DIP is the same thing, minus the 470 lines of other stuff.

writeByte and peekSlice are both @system and can't be called from @safe code though. That won't compile today. What did I miss?
July 19, 2019
On Monday, 15 July 2019 at 15:23:32 UTC, Mike Parker wrote:
> https://github.com/dlang/DIPs/blob/793f83911fdc8c88c6ef34e6a36b5e11e3e574e5/DIPs/DIP1021.md

OK, I think I have a practical example that this DIP enables. Here is a RAII @nogc dynamic array that can be appended to, and exposes individual elements by ref. Before the destructor and `append` could not be marked @trusted because of `maybe_bad` - its ref parameter `i` may have outlived a.data.ptr. Now all methods of Array can be @trusted AFAIK.

struct Array
{
    private int[] data;
    import core.stdc.stdlib;
    @nogc:

    void append(int e) @trusted
    {   // inefficient but it works
        const len = data.length + 1;
        auto ptr = cast(int*)realloc(data.ptr, len * int.sizeof);
        data = ptr[0..len];
    }

    ref int get(size_t i) @trusted return
    {
        return data[i];
    }

    ~this() @trusted
    {
        if (data.ptr) free(data.ptr);
    }
}

@safe:

void maybe_bad(ref Array a, ref int i)
{
    a = Array(); // frees a.data.ptr
    i++;
}

void main()
{
    Array a;
    a.append(5);
    // compiler knows result of `get` is owned by `a`
    // error: Can't pass multiple mutable references owned by `a`
    maybe_bad(a, a.get(0));
}

Walter - is this correct?
July 19, 2019
On Friday, 19 July 2019 at 13:09:29 UTC, Nick Treleaven wrote:
>     void append(int e) @trusted
>     {   // inefficient but it works
>         const len = data.length + 1;
>         auto ptr = cast(int*)realloc(data.ptr, len * int.sizeof);
>         data = ptr[0..len];
>     }

Oops, forgot last line:

        data[$-1] = e;

July 19, 2019
On Friday, 19 July 2019 at 01:32:34 UTC, Walter Bright wrote:
> In fact, the DIP is not necessary if people strictly adhere to RAII.

Bingo. This is why RAII needs to be mentioned, otherwise this DIP is not necessary.
July 19, 2019
On 19.07.19 15:09, Nick Treleaven wrote:
> On Monday, 15 July 2019 at 15:23:32 UTC, Mike Parker wrote:
>> https://github.com/dlang/DIPs/blob/793f83911fdc8c88c6ef34e6a36b5e11e3e574e5/DIPs/DIP1021.md 
>>
> 
> OK, I think I have a practical example that this DIP enables. Here is a RAII @nogc dynamic array that can be appended to, and exposes individual elements by ref. Before the destructor and `append` could not be marked @trusted because of `maybe_bad` - its ref parameter `i` may have outlived a.data.ptr. Now all methods of Array can be @trusted AFAIK.
> 
> struct Array
> {
>      private int[] data;
>      import core.stdc.stdlib;
>      @nogc:
> 
>      void append(int e) @trusted
>      {   // inefficient but it works
>          const len = data.length + 1;
>          auto ptr = cast(int*)realloc(data.ptr, len * int.sizeof);
>          data = ptr[0..len];
>      }
> 
>      ref int get(size_t i) @trusted return
>      {
>          return data[i];
>      }
> 
>      ~this() @trusted
>      {
>          if (data.ptr) free(data.ptr);
>      }
> }
> 
> @safe:
> 
> void maybe_bad(ref Array a, ref int i)
> {
>      a = Array(); // frees a.data.ptr
>      i++;
> }
> 
> void main()
> {
>      Array a;
>      a.append(5);
>      // compiler knows result of `get` is owned by `a`
>      // error: Can't pass multiple mutable references owned by `a`
>      maybe_bad(a, a.get(0));
> }
> 
> Walter - is this correct?

Some problems with this code that don't relate to the DIP:
- It still has a default constructor, so you can call `Array(new int[](10))` and cause a free on a GC pointer.
- The copy constructor is neither implemented nor disabled, so you can easily cause a double free.


I don't think the DIP enables any more code to be @trusted (as it points out in the limitations section).

Consider:

@safe:
class C{
    Array a;
    this(Array a){ this.a=move(a); }
}

void maybe_bad(C c, ref int i){
    c.a = Array();
    i++;
}

void main(){
    auto c=new C(Array());
    c.a.append(5);
    auto d=c;
    maybe_bad(c,d.a.get());
}
July 19, 2019
On 7/19/2019 1:49 AM, Olivier FAURE wrote:
> So I don't understand what the point of this DIP even is, given that for every memory leak that you your DIP prevents, I could give you another way to express it so that your DIP lets it pass.
> It doesn't close a loophole in @safe, because the core problem is that writeByte() isn't actually @safe;

Any container that does its own memory allocation relies on @trusted code.

However, if that container exposes its internals by ref, then it is safe with this DIP, because ref does not span statements.


> Speaking personally, I'm not asking for examples because I don't understand your proposal. The reason I'm asking for examples is that examples are a good medium to support communication, and to suss out the deeper reasons people might disagree about an idea.

It would have facilitated communication if you'd acknowledged you understood the example, but had a question about another specific case (and presented that example).


> I'm pretty sure I do understand your proposal, and I think it's fundamentally flawed. I think you're trying to gradually implement the Rust memory model, and you think that non-aliased function arguments are a good first step, that will help determine how a full implementation should be rolled out. I think that approach is unworkable, because the Rust memory model is kind of an all-or-nothing feature, and gradually implementing it like you intend isn't really feasible; I think DIP 1021, if it passes, will barely be noticed by anyone, except as an annoyance, and won't bring any useful feedback for designing a more coherent memory model.

D has been gradually implementing that memory model for some time now - DIP25 and DIP1000 are examples. This is the next logical step.


> Because, again, DIP 1021 doesn't actually bring any additional memory safety, because "use after free" in real code almost never occurs in a way that could be stopped by DIP 1021.

It's a workable solution for containers that expose pointers to their internals via "ref", because "ref" is a restricted pointer. I've advocated for years that people use "ref" when exposing internals.
July 19, 2019
On Friday, 19 July 2019 at 20:03:22 UTC, Walter Bright wrote:
> On 7/19/2019 1:49 AM, Olivier FAURE wrote:
>> So I don't understand what the point of this DIP even is, given that for every memory leak that you your DIP prevents, I could give you another way to express it so that your DIP lets it pass.
>> It doesn't close a loophole in @safe, because the core problem is that writeByte() isn't actually @safe;
>
> Any container that does its own memory allocation relies on @trusted code.
>
> However, if that container exposes its internals by ref, then it is safe with this DIP, because ref does not span statements.

Counter-example:

    struct S1 {
        byte* ptr;

    @safe:
        ~this() { reset(); }
        ref byte get() return { return *ptr; }

    @trusted:
        void init() { ptr = cast(byte*)malloc(1); *ptr = 0; }
        void reset() { free(ptr); ptr = null; }
    }

    byte* identity(ref return byte b) @safe {
        return &b;
    }

    void useS() @safe {
        S1 s = S1();
        s.init();

        byte* ptr = identity(s.get());
        s.reset();
        *ptr = 1; // BOOM
    }

>> Speaking personally, I'm not asking for examples because I don't understand your proposal. The reason I'm asking for examples is that examples are a good medium to support communication, and to suss out the deeper reasons people might disagree about an idea.
>
> It would have facilitated communication if you'd acknowledged you understood the example, but had a question about another specific case (and presented that example).

I presented that specific problem 22 days ago: https://github.com/dlang/DIPs/pull/158#issuecomment-506633378

You said it didn't apply to your case, which is why I asked you to demonstrate your case. You said your example already did.

I (and several other people) pointed out a non-subjective problem with your example: it doesn't compile any differently before and after the DIP as presented. Which I have repeated several times, and you still haven't acknowledged.

I'm going to repeat that one more time: your example does not compile *any differently* before or after the proposal as you describe it, ***and I'd appreciate if could acknowledge it in any way at all***.

So its power to facilitate communication is kind of null.

Yes, I can make guesses at what you intend. This was, you'll recall, the same argument Manu made for DIP 1016, that the underlying concepts were clear enough, and that there was no need for giving specific semantics because anyone should understand the general concept (you can make references to rvalues).

That's not how a review process works. A reviewer shouldn't have to prove their worth before the submitter includes a single valid example in their proposal (which, I'll note, you still haven't done). Reviewers shouldn't have to write up the examples themselves like we did and conjecture about whether they match the author's intent.

Like, I'm not sure that you realize, but the process of communicating with you is kind of painful and makes me want not to bother at all. You seem to take anybody asking you for additional details as something between a personal insult and an annoying waste of time. In fact, you've spent more time arguing about not writing examples than it took me to write a single example.

In fact, in the three weeks you've been arguing that writing examples was a waste of your time, I've written four different examples trying to understand your proposal.

I'm honestly kind of done here. I'm getting sick of putting effort into understanding your proposal and trying to communicate with you that you're neither matching nor even acknowledging. I'll just work on my own draft and leave this DIP alone.
July 20, 2019
On Friday, 19 July 2019 at 20:03:22 UTC, Walter Bright wrote:
> However, if that container exposes its internals by ref, then it is safe with this DIP, because ref does not span statements.

Timon has disproved this:
https://forum.dlang.org/post/qgsroo$1l8n$1@digitalmars.com

With that struct container as a member of a class, you can have multiple class references to the same class instance and pass one of those to a function with a ref argument of the struct-owned heap memory.
1 2 3 4 5 6 7 8