RFC: moving forward with @nogc Phobos

Oren Tirosh via Digitalmars-d digitalmars-d at puremagic.com
Wed Oct 1 08:48:38 PDT 2014


On Tuesday, 30 September 2014 at 19:10:19 UTC, Marc Schütz wrote:
> [...]
>
> I'm convinced this isn't necessary. Let's take `setExtension()` 
> as an example, standing in for any of a class of similar 
> functions. This function allocates memory, returns it, and 
> abandons it; it gives up ownership of the memory. The fact that 
> the memory has been freshly allocated means that it is (head) 
> unique, and therefore the caller (= library user) can take over 
> the ownership. This, in turn, means that the caller can decide 
> how she wants to manage it.

Bingo. Have some way to mark the function return type as a unique 
pointer. This does not imply full-fledged unique pointer type 
support in the language - just enough to have the caller ensure 
continuity of memory management policy from there.

One problem with actually implementing this is that using 
reference counting as a memory management policy requires extra 
space for the reference counter in the object, just as garbage 
collection requires support for scanning and identification of 
interior object memory range. While allocation and memory 
management may be quite independent in theory, practical high 
performance implementations tend to be intimately related.

> (I'll try to make a sketch on how this can be implemented in 
> another post.)

Do elaborate!

> As a conclusion, I would say that APIs should strive for the 
> following principles, in this order:
>
> 1. Avoid allocation altogether, for example by laziness 
> (ranges), or by accepting sinks.
>
> 2. If allocations are necessary (or desirable, to make the API 
> more easily usable), try hard to return a unique value (this of 
> course needs to be expressed in the return type).
>
> 3. If both of the above fails, only then return a GCed pointer, 
> or alternatively provide several variants of the function 
> (though this shouldn't be necessary often). An interesting 
> alternative: Instead of passing a flag directly describing the 
> policy, pass the function a type that it should wrap it's 
> return value in.
>
> As for the _allocation_ strategy: It indeed needs to be 
> configurable, but here, the same objections against a template 
> parameter apply. As the allocator doesn't necessarily need to 
> be part of the type, a (thread) global variable can be used to 
> specify it. This lends itself well to idioms like
>
>     with(MyAllocator alloc) {
>         // ...
>     }

Assuming there is some dependency between the allocator and the 
memory management policy I guess this would be initialized on 
thread start that cannot be modified later. All code running 
inside the thread would need to either match the configured 
policy, not handle any kind of pointers or use a limited subset 
of unique pointers. Another way to ensure that code can run on 
either RC or GC is to make certain objects (specifically, 
Exceptions) always allocate a reference counter, regardless of 
the currently configured policy.



More information about the Digitalmars-d mailing list