| |
 | Posted by Richard (Rikki) Andrew Cattermole in reply to jmh530 | Permalink Reply |
|
Richard (Rikki) Andrew Cattermole 
Posted in reply to jmh530
| 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).
|