2 days ago
On Wednesday, 7 May 2025 at 23:21:12 UTC, Timon Gehr wrote:
> On 5/7/25 16:47, jmh530 wrote:
>> 
>> I can think of a few different ways forward (by no means limited to just this)
>
> Well, the big issue here is that @live is still not transitive. A function attribute is not really the right way to go about this anyway. Aliasing is a property of a pointer, not a function.

I think the difficulty is figuring a way to convince Walter of this point. It's one thing to assert that it is true, it's another to prove it.

That's why in my last post, I was kind of like, "ok what's the goal, what would we have to do to achieve it." If it can't be achieved with the function attribute approach, then it should be abandoned. But I would hope we can salvage this effort into something useful.

To your point about being a property of a pointer, the alternative approach is to introduce a reference that is borrow checked. Yes, it results in additional pointer types, but if that's the approach that Rust ultimately relies on and it's the only way to achieve what we want, then it's what should be done.
2 days ago

On Thursday, 8 May 2025 at 08:54:16 UTC, Dukc wrote:

>

[snip]
To be honest I didn't think the solution in detail. My intention was just to point out roughly what it would have to be like if @live, is to be useful for @safety but I certainly didn't intend to say it's necessarily the best way to go about it. A totally different borrow checker is also a possibility.
[snip]

Fair points throughout. My reply to Timon applies a bit to what you say here as well.

2 days ago
On 10/05/2025 5:17 AM, jmh530 wrote:
> To your point about being a property of a pointer, the alternative approach is to introduce a reference that is borrow checked. Yes, it results in additional pointer types, but if that's the approach that Rust ultimately relies on and it's the only way to achieve what we want, then it's what should be done.

I want to touch upon this because its misunderstood quite widely regarding the difference between Rust's borrow checker and ownership transfer system.

The borrow checker loosens restrictions placed upon you by the ownership transfer system to give strong guarantees of aliasing and lifetimes. If you did not have the borrow checker, the ownership transfer systems restrictions would make things absolutely impossible to work with.

I'll translate this into D-speak and I'm sure I haven't got it 100%.

For the purposes of this discussion I'll use a non-transitive type qualifier called ``unique`` to indicate ownership transfer, but it can be done other ways like reference counting or isolated from Midori.

When ownership transfer has a variable copied into another, the old variable resets (back to null). You can only have a modelable number of instances of this pointer within a function (could be just one).

By default, any variable (that is a pointer) that is unattributed is equivalent to writing ``unique(int*)``, and ``unique(unique(int*)*)``.

If you add escape analysis annotations it becomes ``int*`` or ``unique(int*)*``.

The former can be passed to the latter implicitly.

```d
void goingDown(unique(unique(int*)*) input) {
	goingUp(input);
}

void goingUp(scope unique(int*)* input) {
	unique(int*) v = *input;
}
```

Now the escape analysis, first you have the going up the stack guarantees, this can be seen in ``goingUp``.

It is where the compiler is establishing the relationships between the variables as seeable by a function prototype.

This is what our DIP1000 attempts to do poorly.

The second kind is in ``goingDown``, and goes by the name borrow checker or as I prefer it "owner escape analysis" and this is what "@live" supposedly fills the gap of (but doesn't).

It adds some extra logic to escape analysis that ``goingUp`` uses, specifically relating to the number of mutable copies you have of it, and requires that object will outlive its borrow.

```d
unique(int*) owner;

{
   int* borrow1 = owner; // ok
   int* borrow2 = owner; // Error
   const(int)* borrow3 = owner; // ok
   owner= null; // Error
}
```

Its important to note here that something has to trigger owner escape analysis. Either the type qualifier or the rest of the escape analysis (via say a function call).

2 days ago
On Friday, 9 May 2025 at 18:28:11 UTC, Richard (Rikki) Andrew Cattermole wrote:
> On 10/05/2025 5:17 AM, jmh530 wrote:
>> To your point about being a property of a pointer, the alternative approach is to introduce a reference that is borrow checked. Yes, it results in additional pointer types, but if that's the approach that Rust ultimately relies on and it's the only way to achieve what we want, then it's what should be done.
>
> I want to touch upon this because its misunderstood quite widely regarding the difference between Rust's borrow checker and ownership transfer system.
>
> The borrow checker loosens restrictions placed upon you by the ownership transfer system to give strong guarantees of aliasing and lifetimes. If you did not have the borrow checker, the ownership transfer systems restrictions would make things absolutely impossible to work with.
> [snip]

Not sure I completely follow everything here, but is your point that to actually do what Rust is doing we need the ownership/borrowing system plus borrow checking?


2 days ago
On 5/4/2025 11:52 PM, Dukc wrote:
> You have to admit this makes our checker, as it currently stands, unusable for what many of us consider the primary purpose of a borrow checker.

The borrow checker works on functions marked with @live. Just like safe checks are only on functions marked @safe. Both are usable.
2 days ago
On 5/7/2025 4:21 PM, Timon Gehr wrote:
> On 5/7/25 16:47, jmh530 wrote:
>>
>> I can think of a few different ways forward (by no means limited to just this)
> 
> Well, the big issue here is that @live is still not transitive.

We are all well aware of the problems with transitive attributes. Making @live transitive means that nobody will ever use it, no matter how good it is. People keep asking for a non-transitive @nogc.

> A function attribute is not really the right way to go about this anyway. Aliasing is a property of a pointer, not a function.

Attaching it to a pointer means nobody will use it, because they'll have to redo their entire program.

2 days ago
On 10/05/2025 7:15 AM, jmh530 wrote:
> On Friday, 9 May 2025 at 18:28:11 UTC, Richard (Rikki) Andrew Cattermole wrote:
>> On 10/05/2025 5:17 AM, jmh530 wrote:
>>> To your point about being a property of a pointer, the alternative approach is to introduce a reference that is borrow checked. Yes, it results in additional pointer types, but if that's the approach that Rust ultimately relies on and it's the only way to achieve what we want, then it's what should be done.
>>
>> I want to touch upon this because its misunderstood quite widely regarding the difference between Rust's borrow checker and ownership transfer system.
>>
>> The borrow checker loosens restrictions placed upon you by the ownership transfer system to give strong guarantees of aliasing and lifetimes. If you did not have the borrow checker, the ownership transfer systems restrictions would make things absolutely impossible to work with.
>> [snip]
> 
> Not sure I completely follow everything here, but is your point that to actually do what Rust is doing we need the ownership/borrowing system plus borrow checking?

Strictly speaking no.

What you need is escape analysis with relationship strengths.

```d
struct Owner {
    int* borrow() @escape(return^) { ... }
}

Owner owner = ...;
int* ptr = owner.borrow;
owner = Owner.init; // Error
```

The escape attribute there, upgrades the escape to protecting the this pointer for as long as the borrow exists.

DIP1000 has two relationship strengths, for this we need a third.

This triggers the borrow checking aspect to escape analysis.
Without it, it can't trigger per variable.

The main problem is how costly the data flow analysis of doing this is, to an extent that models enough code to both be useful and fast.

I think I've solved this part of the problem, and am currently implementing the first portion of it up to a proof of concept stage.

2 days ago
On 5/7/2025 6:27 PM, Meta wrote:
> And this is exactly what Rust does with the borrowed/raw pointer distinction. Walter how can you claim to have studied the Rust spec yet miss and/or disregard this fundamental detail?

I did not miss it. See my reply to Timon.


> And do not bring up that extremely outdated and irrelevant example of near/far pointers in DOS.

Yes it is dated, as modern languages abandoned multiple pointer types based on that experience.

The only one I even know about is Microsoft Managed C++, where they have gc and nogc pointers. What a disaster. Nobody wants to write code in Managed C++. That scheme never made it into Standard C++.

A feature needs to be useful and easy to use in order to get people to use it.

2 days ago
On 5/9/2025 11:28 AM, Richard (Rikki) Andrew Cattermole wrote:
> This is what our DIP1000 attempts to do poorly.

The concept of DIP1000 is solid. It does an excellent job (sans bugs) of preventing escaping pointers to the stack.

The problem is fitting it into the various high level constructs that D has, and the confusing attributes needed to inform the function interface of the status of its arguments.

DIP1000 does not need to do flow analysis, and does not attempt it, but the borrow checker does need it.

2 days ago
The @live design was done in a manner to not need any new syntax - it is an extra layer of error checking.