DIP60: @nogc attribute

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Mon Apr 21 05:00:50 PDT 2014


On Fri, 18 Apr 2014 20:17:59 -0400, Walter Bright  
<newshound2 at digitalmars.com> wrote:

> On 4/18/2014 5:30 AM, Steven Schveighoffer wrote:
>> Absolutely not, the compiler knows whether the count needs to be  
>> incremented, I
>> don't need to know.
>
> But there are manual escapes from it, meaning you need to know to use  
> them:
>
>     unsigned char *vdata = data.data;
>     // process vdata
>
> I am skeptical that the O-C compiler is sufficiently smart to make ARC  
> on all pointers practical. That snippet pretty much proves it.

I finally understand what you are saying.

Yes, when my code devolves into C-land, I have non-ARC pointers. This  
means I cannot store these pointers somewhere if I don't keep a pointer to  
the object that owns them. This is indeed manual memory management.

But, and this is a big but, I DON'T have to care about memory management  
as long as I only store pointers to objects, aside from the stack. Objects  
themselves can store non-ARC pointers and manage them privately, but not  
allow arbitrary setting/getting of pointers. This is not very common.

A great example of where I use arbitrary non-GC pointers, is an object  
that stores a network packet.

unix sockets work just fine in networking and iOS, so I do all of my  
networking with socket, send, recv, etc.

These functions take unmanaged char * pointers.

So an object that stores a single packet does this:

1. read the packet header into a structure overlay. Figure out the length  
(this is a TCP packet).
2. malloc a char array with the proper length, read in the packet.
3. verify the packet is correct, if not, free the buffer.
4. If it's correct, digest the packet (storing fields from the packet data  
itself, byteswap, etc.). Then store the data into an NSData object, giving  
it ownership of the buffer.

All this happens within a factory method. I never directly store the char  
* array inside the object or elsewhere, it gets wrapped into an NSData  
object, which will then free the data once the object is destroyed.

You must be conscious about memory management, because after all,  
Objective-C *is* C, and you are allowed to do stupid things just like in  
C. But you CAN have a certain set of rules, and as long as you follow  
those rules, you will not have to deal with memory management.

> Total replacement of GC with ARC in D will:

This is the wrong straw-man, I'm not advocating for this at all.

> 1. Be a massive change that will break most every D program
> 2. Require people to use unsafe escapes to recover lost performance
> 3. Require multiple pointer types

This isn't what I had in mind anyway. I envisioned an ARC system like  
Objective-C, where the type pointed at defines whether it's ARC or GC.

For instance, GC would be *required* for array appending in D, because  
arrays cannot be ARC-managed. You would need a wrapper type for ARC, with  
it's own semantics.

> 4. Will not be memory safe (see (2))
> 5. Require the invention of optimization technology that doesn't exist

Besides being a tautology, what does this mean?

> 6. Become more or less ABI incompatible with C without a long list of  
> caveats and translations

Again, this is based on your straw-man which I don't advocate for. The  
change I had in mind was much less invasive.

> A much more tractable idea is to implement something like C++'s  
> shared_ptr<> as a library type, with usage strategies paralleling C++'s  
> (and yes, use of shared_ptr<> would be unsafe).

shared_ptr would work (and I've used that extensively too, it's awesome  
for C++), but I feel it's a much less effective solution than a  
compiler-augmented system that can optimize away needless  
increment/decrements.

Note that shared_ptr would never be able to handle D's slice appending  
either.

-Steve


More information about the Digitalmars-d mailing list