On Sunday, 2 February 2014 at 07:35:21 UTC, Andrei Alexandrescu wrote:
What I'm driving at is that right now the type is A, as is in a variety of other situations. It would be a whole different language that would be wholly incompatible with D.

A == Borrowed!A in my view. Consider this:

class A { A foo() { return this; } }

A a;

void crashy() {
   ubyte[__traits(classInstanceSize, A)] Abuffer;
   auto localA = emplace!A(Abuffer);

   a = localA.foo();
}


That's obviously wrong, when crashy returns, a is dead... but it has no way of knowing that.

Let's consider we wrote a nice little Owned!T. Internally, it keeps that buffer, disables postblit, frees in the destructor and might have a release method to transfer ownership. All stuff we can do in the library today.


Owned!A a;
void crashy() {
   Owned!A localA = Owned!A();
a = localA; // prohibited, this(this) is annotated with @disable a = localA.foo(); // should ALSO be prohibited, cannot convert A to Owned!A
}


The class object itself doesn't know how it is stored. If it returns this, it MUST assume it is borrowed unless it explicitly allocates a new thing.

For all it knows, it was emplaced into a static array or malloced. A == Borrowed!A. typeof(this) == A.




So, what about the global a up there? I think there's two solutions:

1) ideally, Owned!A has something like this:

scope A borrow() { return payload; }
alias borrow this;

A a = localA; // legal, A is a local variable in the same or inner scope globalA = localA; // illegal, since borrow returns scope, it isn't allowed to escape


2) a worse but perhaps doable option would be

A globalA; // illegal, non-local variable must not be borrowed

struct foo {
A a; // now foo is itself considered a borrowed reference type so the rules apply to it
}

GC!A globalA; // ok cool



What's interesting about this is we could, in theory (and I've done a limited proof of concept), implement it in the library using a static assert in RTInfo!

anyway i g2g might talk more later

Reply via email to