Borrowing and Ownership
Timon Gehr
timon.gehr at gmx.ch
Wed Nov 13 09:52:24 UTC 2019
On 13.11.19 09:08, Atila Neves wrote:
> On Sunday, 27 October 2019 at 22:36:30 UTC, Timon Gehr wrote:
>> I finally got around to writing up some thoughts on @safe borrowing
>> and ownership in D.
>
> Thanks! I'd been wanting to understand your thoughts on this for a
> while. A few questions:
>
>> ref implies scope
>
> Is that true now??
> ...
Yes. (What I mean is that it applies to the implicit pointer that is
generated, not the value itself.)
For example (compiled with -dip1000 switch):
int* p;
void foo(ref int x)@safe{
x=2;
p=&x; // error
}
void main()@safe{
int x;
foo(x);
}
error: address of variable `x` assigned to `p` with longer lifetime
>> `scope` should apply to all types of data equally
>
> And how would the application of `scope` to, say, `int` affect it? What
> would the compiler do with that?
> ...
The same things it would do with other types. You can't escape the value
or make non-borrowed copies. It's unlikely to have useful applications
for a plain integer, but you could have a `struct Handle{ private int
handle; ... }` that carries the invariant that the handle is valid.
Then you can do things like:
void workWithHandle(scope Handle handle)@safe{ ... }
void unsafe()@trusted{
auto handle=getHandle();
workWithHandle(handle);
disposeHandle(handle);
}
If `scope` was restricted to pointers, you would have to pass pointers
to handles in order to get any of that type checking. (IIRC, this
complaint was on this newsgroup not too long ago.) In general, it would
make the rules less useful for @trusted libraries that need to restrict
access patterns from @safe code.
> Could you please expand on the rationale for these rules?
> ...
As noted, with DIP 1021 accepted, it's pretty clear that mutable `scope`
pointers won't be able to alias (as that DIP attempts to restrict
aliasing of `ref` parameters). I would prefer to keep aliasing and
lifetime restrictions separate (because you can always assign something
with higher lifetime to something with smaller lifetime, but aliasing
restrictions are incompatible both ways), but it's unlikely to happen.
Note that Walter's vision for @live is to restrict aliasing in this way
for _all_ pointers.
>> Non-immutable non-scope values may not be assigned to `scope` values
Otherwise you could very easily introduce aliasing between scoped pointers:
void foo(int* p)@safe{
scope int* q=p;
scope int* r=p;
assert(q !is r); // fail
}
The type system is supposed to guarantee that if this assertion
compiles, it passes.
>> A non-`scope` pointer cannot be dereferenced if that would yield a
>> `scope` value
A non-scope pointer doesn't satisfy any aliasing restrictions, hence if
you dereference it and get a `scope` value, you could have multiple
paths to access a single `scope` value, which has to be ruled out.
void foo(scope(int*)* p, scope(int*)* q)@safe{
// p and q could alias
scope int* r=*p;
scope int* s=*q;
assert(r !is s); // can fail
}
>> `scope` has to be a type constructor.
>
One example:
import std.typecons;
int* y;
int* foo(){
int x;
auto t=tuple(&x,y); // type has to be Tuple!(scope(int*),int*)
return t[1];
}
(Another key use case for type constructors is to distinguish the return
value and the receiver, as in `const(int*) foo()const`;, but for
`scope`, we can actually write `int* foo()scope return` for this purpose.)
> Other than that, I wonder about the teachability of these rules.
The rules follow from the simple principles lined out at the beginning
of the post, so that should not be a problem. Note that my post was
pretty condensed. Unfortunately, I don't have enough spare time at the
moment.
> I had to read the proposal several times myself.
>
Thanks for taking the time.
More information about the Digitalmars-d
mailing list