Smart pointers instead of GC?

Frank Bauer y at z.com
Sun Feb 2 12:29:31 PST 2014


+1 on making Phobos GC-free.

On Sunday, 2 February 2014 at 07:35:21 UTC, Andrei Alexandrescu 
wrote:
> On 2/1/14, 10:00 PM, Frank Bauer wrote:
>> On Sunday, 2 February 2014 at 05:41:53 UTC, Andrei 
>> Alexandrescu wrote:
>>> Sure. While you're young typecheck this:
>>>
>>> class A {
>>>   auto stuff() { ...; return this; }
>>> }
>>>
>>>
>>> Andrei
>>
>> It would be a Borrowed!A, I would say, no matter how an A is 
>> allocated.
>> A GC!A, an ARC!A and an Owning!A convert equally well to a 
>> Borrowed!A.
>> As long as the Borrowed!A is in use (i.e. scope) after stuff() 
>> returns,
>> the A object must not be freed (compiler enforced). Would that 
>> make sense?
>
> No.
>
> 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.
>
>
> Andrei

Why is that? I propose the new memory regime to be 100% 
compatible with all existing D code. It is way more powerful than 
anything scope can do. And it seems a lot less work to me than 
going through GC optimization and custom allocator tracing hell.

Let's see how far we can get if we require none of the existing D 
code to break.

Example: this is current D code that runs unchanged and with the 
same semantics under the new memory regime. GC(T) and Borrowed(T) 
remain under the hood:

class A {
     A foo() { return this; }   // returns Borrowed!A
}

void main () {
     A m1 = new A;   // m1 is a GC!A
     A m2 = m1;      // m2 is a Borrowed!A
     A m3;           // Borrowed!A
     m3 = m1;        // fine: assignment from GC!A to Borrowed!A
     m3 = bar(m1);   // fine: m1 converted from GC!A to 
Borrowed!A, assignment from Borrowed!A to Borrowed!A
     m3 = bar(m2);   // fine: m2 already Borrowed!A, assignment 
from Borrowed!A to Borrowed!A
     m1 = new A;     // fine: can reasssign GC!A although there 
are outstanding references
     m1 = m2;        // fine: can reassign GC!A to a Borrowed!A
}

A bar(A a) {        // takes and returns Borrowed!A
     A b1 = a;
     return b1;
}

Now here it comes: if, on the other hand, I replace the first 
'new' with, say e.g., 'newOwning' (or '~', whatever), I get 
GC-free code:

A m1 = newOwning A; // m1 is an Owning!A, allocating on the heap 
and freeing when it goes out of scope

Then these lines above would be in error:

     m1 = new A;     // error: can't reassign to m1 because m2 and 
m3 still referencing m1 (same for newOwning)
     m1 = m2;        // error: can't assign Borrowed!A to Owning!A

ARC(T) could be implemented similarly.

Nothing changes one bit for those who want to use the GC as 
before. ARC(T) and Owning(T) would be *ADDED* on top of the 
existing language spec.

Emplacement new, as Adam mentioned, is not a problem: you always 
get to the emplaced object with a Borrowed!T. The underlying 
memory is managed separately and automatically as a GC!M, ARC!M 
or Owning!M (M could be an array of bytes, e.g.).


More information about the Digitalmars-d mailing list